[comp.lang.misc] Double Width Integer Multiplication and Division

cik@l.cc.purdue.edu (Herman Rubin) (07/05/89)

In article <255@obs.unige.ch>, bartho@obs.unige.ch (PAUL BARTHOLDI) writes:
> In article <1989Jun26.195044.4197@cs.rochester.edu>, crowl@cs.rochester.edu (Lawrence Crowl) writes:
> >>When we were [designing integer division support on the MIPS processors], we
> >>couldn't think of any languages whose natural implementation on a 32-bit
> >>machine would expect generation of a 64 by 32 bit divide as the expected
> >>operation.  Does anybody know of any such, or is this strictly something one
> >>would use in handcoded routines?
> >  
> > Languages which support fixed-point arithmetic, e.g. PL/I and Ada, could use
> > such a feature to substantially improve fixed-point performance ...

	[There follows a discussion of how this happens in FORTH]

The language designers did not put something in the language, therefore the
hardware people do not put it on the machine, therefore the new language
designers do not put it in the language, and the recursion continues.  Despite
the claims of the Algolniks, there has been no language which comes close to
treating what I consider the hardware-natural operations which I would find
useful.  Many of them were present 35 years ago on a larger proportion of
machines than now.

What languages, other than Lisp and some similar ones, have the idea that
an operation or function can return a string of values?  What languages allow
the user to introduce addition operator symbols?  A few allow additional types.
Now these deficiencies in languages go back to day 1.

What is double precision?  We first need to know what single precision is.
And (no surprise) it is different on different machines, and can even be
different for addition and multiplication on the same machine.  On the
CRAY, for integer addition one can use 64-bit 2's complement numbers.
But for multiplication, only 48-bit sign-magnitude mantissas.  However,
the best integer multiplication possible is 24x24->48.  And all division
has to be programmed.

The CYBER 205 has only 48-bit 2's complement numbers for arithmetic.
There are even problems in integer addition.  But a double length product
can be produced with two multiplies, with minor problems.  Floating point
division is present, but fixed point must be programmed.  Interesting
things can be done with vectors, and a programmed 32x32->64 inner product
might be a good idea.

Now if you define single precision as 16 bits, a 32-bit machine is 
automatically double-precision.  If you define it as 256 bits, you
would need 256x256->512 and 512/256 giving a 256-bit quotient and
remainder to have double precision.  For those needing good integer
arithmetic, the bigger the better.  And a few machine operations make
a big difference.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

suitti@haddock.ima.isc.com (Stephen Uitti) (07/06/89)

In article <1387@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>What languages, other than Lisp and some similar ones, have the idea that
>an operation or function can return a string of values?

C.  One can pass structures and unions back & forth by name or
value.  While it is true that some C compilers are broken when
passing large things by value, it has been defined in the
language since 1978.  OK, so the syntax is a little awkward in
that you have to define the structures, but at least it tends not
to add large amounts of additional overhead.  Also, in C, people
commonly use the code sequences:
caller:
	int i, j;
	char *p;
	i = foo(&j, &p);
callie:
	int foo(j, p)
	int *j;
	char **p;
	{
		*j = secondvalue;
		strcpy(*p, "third value");
		return value;
	}
Which is OK, as long as the interface is properly documented.

Now you want the language to use syntax that YOU defined?
Compiler writers are doing that now too.  I'd rather they spent
their time on designing unambiguous and coherant languages for
which code can be easily written, read and modified, that have
real scope rules for libraries and other seperately compiled
environments, and produce more optimal code for real machines,
and provide for special needs of real people in the way of
specialized preprocessors (lex, yacc) and prewritten library
code.

>What languages allow the user to introduce additional operator
>symbols?  A few allow additional types.  Now these deficiencies
>in languages go back to day 1.

C++ and Ada.  My wristwatch (Casio) has more compute resources
than was available on day 1.  I don't expect it to allow
additional operators and types either.  It does have a 64 bit
(BCD) divide.  Throw out your '205 and get a Casio.

Stephen.

khb@gammara.Sun.COM (gammara) (07/06/89)

In article <13946@haddock.ima.isc.com> suitti@haddock.ima.isc.com (Stephen Uitti) writes:
>In article <1387@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>
>>What languages allow the user to introduce additional operator
>>symbols?  A few allow additional types.  Now these deficiencies
>>in languages go back to day 1.
>
>C++ and Ada.  My wristwatch (Casio) has more compute resources
>than was available on day 1.  I don't expect it to allow
>additional operators and types either.  It does have a 64 bit
>(BCD) divide.  Throw out your '205 and get a Casio.

Well, as long as we are leaving .arch and moving to .lang :>,
Fortran8x has operator overloading and user defined operators.



Keith H. Bierman      |*My thoughts are my own. Only my work belongs to Sun*
It's Not My Fault     |	Marketing Technical Specialist    ! kbierman@sun.com
I Voted for Bill &    |   Languages and Performance Tools. 
Opus  (* strange as it may seem, I do more engineering now     *)

cik@l.cc.purdue.edu (Herman Rubin) (07/06/89)

In article <13946@haddock.ima.isc.com>, suitti@haddock.ima.isc.com (Stephen Uitti) writes:
> In article <1387@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> >What languages, other than Lisp and some similar ones, have the idea that
> >an operation or function can return a string of values?
> 
> C.  One can pass structures and unions back & forth by name or
> value.

NO!.  For the n-th time, a list is not a struct.  A struct is a memory
allocation scheme.  It presumes a particular "physical" ordering of the
items.  Even if one can implement a struct in registers, it still 
restricts which registers are used far more than a list does.  For
example, on a machine in which there is division yielding a quotient
and a remainder, I want to write

	q,r = x/y;

On the VAX, for example, q could be in register 3 and r in register 10.
Since the hardware allows simple things like this, the language should.
At the present time and in the future, loads and stores must slow things
down unless they can be overlapped.  The overlapping problem is greatly
exascerbated by having to do too many of them.
> 
> Now you want the language to use syntax that YOU defined?
> Compiler writers are doing that now too.  I'd rather they spent
> their time on designing unambiguous and coherant languages for
> which code can be easily written, read and modified, that have
> real scope rules for libraries and other seperately compiled
> environments, and produce more optimal code for real machines,
> and provide for special needs of real people in the way of
> specialized preprocessors (lex, yacc) and prewritten library
> code.

How many people would have difficulty with the above quotient-remainder
notation even without explanation?  With commenting, lots more could be
done without difficulty.  A struct is more complicated than a new type.
>
> >What languages allow the user to introduce additional operator
> >symbols?  A few allow additional types.  Now these deficiencies
> >in languages go back to day 1.
> 
> C++ and Ada.  My wristwatch (Casio) has more compute resources
> than was available on day 1.  I don't expect it to allow
> additional operators and types either.  It does have a 64 bit
> (BCD) divide.  Throw out your '205 and get a Casio.
> 
I am not very familiar with Ada.  C++ allows the introduction of new
types, although they are not called types.  The stupid use of the word
"typedef" in C rather than the more accurater "typealias" is responsible
for this.  But I do not believe that C++ or Ada allows one to define
symbols or symbol combinations as infix operators.  As a simple case,
I should be able to tell the compiler that \ is the bit clear operation,
which &~ may or may not handle properly, and has the same machine
structure as OR on the VAX (or any other machine which has it in
hardware.)  If I am using a 205, I will use an algorithm appropriate
for the 205.  If I am using a CRAY, I will use an appropriate one.
If it involves double precision multiplication or square root, I will try
hard to find a workaround on the CRAY.


-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

' Sabatella) (07/07/89)

>	q,r = x/y;

Back in school, we learned a language that allowed this sort of thing.
It may have been the language "Clu", from MIT, but I am not sure.

>>>What languages allow the user to introduce additional operator
>>>symbols?
>> 
>> C++ and Ada.
>
> But I do not believe that C++ or Ada allows one to define
>symbols or symbol combinations as infix operators.

I don't know about C++, but Ada certainly does have this ability:
you simply define a function something like this:

	function "\" (in x, y:integer) returns integer is begin ... end;

modulo my rusty syntax.

suitti@haddock.ima.isc.com (Stephen Uitti) (07/07/89)

In article <1388@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>> >What languages, other than Lisp and some similar ones, have
>> >the idea that an operation or function can return a string of values?
>> C.  One can pass structures and unions back & forth by name or
>> value.
>NO!.  For the n-th time, a list is not a struct.  It presumes a
>particular "physical" ordering of the items.

LISP does not actually pass whole lists around - it uses pointers
and linked lists.  In C, linked lists are typically implemented
with a struct for each node.  There are no lists in C, but
structs can be lists.

You wanted to have a function be able to return more than one
item.  I suggested two syntactic solutions: returning a struct,
or having the caller specify where to put the answers.  When it
comes down to it, you don't want the compiler to necessarily
generate a function with call/return overhead.  You really want
functions or intrinsics that the compiler can turn into inline
code.  You are thinking of inline code as a single instruction,
though i'm not limiting this to anything that simple.

Is there anything really evil with this:
	q = divrem(top, bottom, &remainder);
Divrem can "return" q, and stuff "remainder" where it is supposed
to go.  Compilers are getting smart enough to do this the way you
want it.  This is documentable.  This is manageable.  Type
checking can be done everywhere to reduce the error rate.

Let's say you have a '205 and a VAX.  You want to develop your
code on the VAX, because it has better debuggers, faster response,
and it is much cheaper than '205 time.  If you break the grammer
of your standard language, then you have to break it for both
machines.  The above 'divrem' function can be written in real C,
and a (slow) version can run, and be debugged on the VAX.  Then,
the very same code can be run on the target machine.

The way '205 C's vector stuff was actually done broke all sorts
of things.  Writing portable high speed code required heavy
ifdefs for each application.  It could have been done in a manner
that a simple library could be written for the VAX (etc.) that
would allow the code to be just run.

>I want to write
>	q,r = x/y;
Unfortunately, this already means something in C.

>On the VAX, for example, q could be in register 3 and r in register 10.

The syntax i suggested above would not require things to be in
any given place.  The compiler should be able to figure this
sort of thing out.

>Since the hardware allows simple things like this, the language should.

The language does.  It just doesn't allow you to do it with the
syntax you want.  This is (by comparison to register allocation
and procedure inlining) a hard problem.  Languages that have
fixed syntax are difficult enough to prove unambiguous.  If the
language allows free redefinition, it is easy for the user to
generate something that can't be parsed.  It took years to get a
real Ada compiler to work.

>At the present time and in the future, loads and stores must slow things
>down unless they can be overlapped.

Or optimized out.

>The stupid use of the word "typedef" in C rather than the more
>accurater "typealias" is responsible for this.

OK, so the terminology for C is a little broken.  I've used
languages that have (for example) German words for keywords.
That didn't mean that i felt the need to change the language's
syntax or terminology.

>As a simple case,
>I should be able to tell the compiler that \ is the bit clear operation,
>which &~ may or may not handle properly, and has the same machine
>structure as OR on the VAX.

How do you want to tell it what the operator means?  Do you want
to give it an assembler template?  Do you want to give it an
algorithm already expressible in the language?  If it is
assembler, you probably want gcc's asm feature that allows
symbolic names to be given to assembler arguments.  Then, if it
turns out to be more complicated, you might try preprocessor
macros.  If it turns out to be more complicated than that, you
might put it into an inlineable function.  Otherwise, it should
probably be a true function.  You may already have the tools you need.

Stephen.

cik@l.cc.purdue.edu (Herman Rubin) (07/07/89)

In article <13961@haddock.ima.isc.com>, suitti@haddock.ima.isc.com (Stephen Uitti) writes:
> In article <1388@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
> >> >What languages, other than Lisp and some similar ones, have
> >> >the idea that an operation or function can return a string of values?
> >> C.  One can pass structures and unions back & forth by name or
> >> value.
> >NO!.  For the n-th time, a list is not a struct.  It presumes a
> >particular "physical" ordering of the items.
> 
> LISP does not actually pass whole lists around - it uses pointers
> and linked lists.  In C, linked lists are typically implemented
> with a struct for each node.  There are no lists in C, but
> structs can be lists.

And this is the reason that production programs and library subroutines
should not be written in Lisp.  But it is possible to get much done
efficiently.  This should be done by enabling those who can see how
to do things to do them and to communicate that to others.  Anything
can be done on a universal Turing machine, but I am not willing to
wait a month for it to multiply two 10-digit numbers by reducing
everything to successor.

> You wanted to have a function be able to return more than one
> item.  I suggested two syntactic solutions: returning a struct,
> or having the caller specify where to put the answers.  When it
> comes down to it, you don't want the compiler to necessarily
> generate a function with call/return overhead.  You really want
> functions or intrinsics that the compiler can turn into inline
> code.  You are thinking of inline code as a single instruction,
> though i'm not limiting this to anything that simple.
> 
> Is there anything really evil with this:
> 	q = divrem(top, bottom, &remainder);
> Divrem can "return" q, and stuff "remainder" where it is supposed
> to go.  Compilers are getting smart enough to do this the way you
> want it.  This is documentable.  This is manageable.  Type
> checking can be done everywhere to reduce the error rate.

There are three things wrong with this.  First, I do not know of 
any version of C which can pass the address of a register.  In
fact, I know of few machines in which that construct makes sense.
And how would you pass it, anyhow?

The second is that I do not want the compiler to even think that this
should be a subroutine call.  For what I consider obvious, I should not
have to rely on the compiler writer being equally astute.  Of course,
this is only the case if the hardware is on the machine.  But even if
not, it probably should be inlined.

The third is, in my opinion, the most important.  It is why I execrate
most of the present assembler languages.  Notation is very important.
For example, I consider the introduction of algebraic symbols by
Diophantus as one of the really great contributions to mathematical
communication.  In fact, I would make it THE mathematical requirement
for admission to college.  But the same holds for algebraic operators.

I am no more willing to write 	q = divrem(top, bottom, &remainder);
every time I want to use it than you are to write  x = sum(y,z);
In fact, I would consider the first as more confusing notationally
than the second.  Is it any easier for a human to read than

	q,r = top/bottom;

What about

	exp,mant =UP (d);

to unpack a double into an int exponent and a double long mant, both to
be in registers?  I have used this.

> Let's say you have a '205 and a VAX.  You want to develop your
> code on the VAX, because it has better debuggers, faster response,
> and it is much cheaper than '205 time.  If you break the grammer
> of your standard language, then you have to break it for both
> machines.  The above 'divrem' function can be written in real C,
> and a (slow) version can run, and be debugged on the VAX.  Then,
> the very same code can be run on the target machine.
> 
What gives you the impression that I would want to use the same
code on a 205 and a VAX?  I have used both machines, and I would
consider it a mistake much of the time.  On the VAX I would use
a long long, but on the 205 only a one-word integer.  To me they
are somewhat different.  Only at the bright human level should one
consider a common code.  For division with remainder, the code should
be machine language, not C.  Would you use C to do machine-independent
implementation of division?  You would not think of it.  Neither would
I think of making similar operations such as frexp, divrem, exponentiation,
absolute value, integer part, etc., machine independently coded in C.
I would not consider coding the =UP above in C.  It is an additional
primitive operation, like +, *, /, &.

> The way '205 C's vector stuff was actually done broke all sorts
> of things.  Writing portable high speed code required heavy
> ifdefs for each application.  It could have been done in a manner
> that a simple library could be written for the VAX (etc.) that
> would allow the code to be just run.

I consider the 205 hardware the best designed vector hardware I have
seen.  It is the C language which is inadequate.  And there is a severe
limit to what should be portable.

> >I want to write
> >	q,r = x/y;
> Unfortunately, this already means something in C.

What does it mean?  Would putting the q,r in parentheses or something else
avoid the conflict?  The use of a list to the left of the = should have
been noticed as a deficiency in the languages 35 years ago.  

> >On the VAX, for example, q could be in register 3 and r in register 10.
> 
> The syntax i suggested above would not require things to be in
> any given place.  The compiler should be able to figure this
> sort of thing out.

I have yet to see a fair compiler.

> >Since the hardware allows simple things like this, the language should.
> 
> The language does.  It just doesn't allow you to do it with the
> syntax you want.  This is (by comparison to register allocation
> and procedure inlining) a hard problem.  Languages that have
> fixed syntax are difficult enough to prove unambiguous.  If the
> language allows free redefinition, it is easy for the user to
> generate something that can't be parsed.  It took years to get a
> real Ada compiler to work.

It is not hard.  I will very gladly settle for a highly flexible easily
written simple language.  The problem is that there are a limited number
of basic macro substitutions in the present languages, and because of this,
elegance is attempted.  If the language had to allow for the user using the
same types of macros, more simplicity would be required.

> >At the present time and in the future, loads and stores must slow things
> >down unless they can be overlapped.
> 
> Or optimized out.

I consider a programmer quite inept who does not know what is temporary and
what is not.  I consider someone quite bright who can look over code not
making this distinction and figure it out.  A compiler is fast, but does
not compare in intelligence with a human imbecile.

> >The stupid use of the word "typedef" in C rather than the more
> >accurater "typealias" is responsible for this.
> 
> OK, so the terminology for C is a little broken.  I've used
> languages that have (for example) German words for keywords.
> That didn't mean that i felt the need to change the language's
> syntax or terminology.

There is a difference between using a German word and using an incorrect
word.  There were languages before C which allowed the user to define types.
K&R even comment that "typedef" does not allow one to define a new type.

Also, computer language and system people seem prone to taking standard
mathematical symbols and using them for other purposes, even to the extent
that the standard use is precluded by it.

> >As a simple case,
> >I should be able to tell the compiler that \ is the bit clear operation,
> >which &~ may or may not handle properly, and has the same machine
> >structure as OR on the VAX.
> 
> How do you want to tell it what the operator means?  Do you want
> to give it an assembler template?  Do you want to give it an
> algorithm already expressible in the language?  If it is
> assembler, you probably want gcc's asm feature that allows
> symbolic names to be given to assembler arguments.  Then, if it
> turns out to be more complicated, you might try preprocessor
> macros.  If it turns out to be more complicated than that, you
> might put it into an inlineable function.  Otherwise, it should
> probably be a true function.  You may already have the tools you need.

Whatever is appropriate.  But the C preprocessor, or any other present
macro language in my ken, will not do it.  A macro template processor,
in which the macro "name" is scattered through the macro, and which is
weakly typed and may even use storage classes, would do the job.

For example, I would consider x ={t} y - z the "=-" macro with arguments
x, y, and z.  Its precise meaning involves the types of the arguments,
unless the optional t field is present, which overrides the type.  A more
complicated one is the basic vector operation collection on the 205, which
could be written

	c{'z} ={t} {-}{|} a{'x} OP{m} {|} b{'y} {/\{~}w}

Here we have the "=OP" macro with 3-7 arguments and 10 optional fields.
Since the fields operate independently and simply, this is not really
difficult.  If a or b is scalar, the displacement fiels following
them must be absent, and if OP is Boolean, the - and | fields must
be absent, etc.  So what?  With such a macro processor, I would not
be too inconvenienced by the lack of a compiler.

> Stephen.

The value of a compiler and language is ease of programming.  In this,
notation and flexibility are extremely important.  If a mathematician
finds notation missing, he invents it for his paper.  It may or may not
be adopted by others, but that does not prevent people from reading his
paper.

The same should hold for languages and compilers.  If I see a missing
construct, I should be able to define it using the power of the machine
on which I intend to run it.  A simple example of the lack of desirability
of C portability is the addition of two vectors.  The good coding of this
depends on the costs of the *x++ in loading and storing and the use of
index in loading and storing.  These depend both on the machine and the
storage classes of the adresses.  There are others.  A good programmer
must know these things and discuss the alternatives with the user.  This
is even the case if the programmer and user are the same person.
flexibility are important.
-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

peter@ficc.uu.net (Peter da Silva) (07/07/89)

In article <1388@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
> For example, on a machine in which there is division yielding a quotient
> and a remainder, I want to write

> 	q,r = x/y;

(1) What does this do when no such operation exists?
(2) How does this fit in with the rest of the expression syntax?
(3) Get a good optimiser and say:
	q = x/y;
	r = x%y;
(4) Is it obvious which is the quotient and which is the remainder
    when you have something like:
	tens,relx = muscle0.fiber/potential;
(5) What if x or y contain other operations that could require a
    quotient or remainder?
(6) What does this mean:
	q,r,s = x/y/z;
(7) What does this sort of micro-optimisation gain you? Except in a
    tight loop, very little. Since you're intending to be machine-
    specific anyway, why not squirrel that loop away in an assembly
    routine?
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "WHAT HAPPENED TO ALL
Personal: peter@sugar.hackercorp.com.   `-_-' |  THE WOMEN IN TEXAS?"
Quote: Have you hugged your wolf today?  'U`  |  -- ACS1W@jane.uh.edu (meesh)

byrd@portia.Stanford.EDU (Greg Byrd) (07/08/89)

In article <13961@haddock.ima.isc.com> suitti@haddock.ima.isc.com (Stephen Uitti) writes:

[original posting about returning multiple values...]

>LISP does not actually pass whole lists around - it uses pointers
>and linked lists.  [stuff deleted]
>
>You wanted to have a function be able to return more than one
>item.  [more stuff deleted]

Just wanted to point out that you *can* return multiple values in
Lisp without returning a list -- e.g., the 'values' and 
'multiple-value-bind' forms in Common Lisp.


...Greg Byrd
   Stanford University

suitti@haddock.ima.isc.com (Stephen Uitti) (07/08/89)

>For division with remainder, the code should
>be machine language, not C.  Would you use C to do machine-independent
>implementation of division?  You would not think of it.  Neither would
>I think of making similar operations such as frexp, divrem, exponentiation,
>absolute value, integer part, etc., machine independently coded in C.
>I would not consider coding the =UP above in C.  It is an additional
>primitive operation, like +, *, /, &.

Not only would i think of it, i've done it.  A check is made to see that
the compiler really generates the right instructions.

>I consider the 205 hardware the best designed vector hardware I have
>seen.

No real debate here.  The '205 was a real ambitious project.
Very, very difficult and costly to maintain, but real nice.
Current RISC machines are also ambitious, but in a differant way.
The goal is to make something simple enough to support that is
also fast enough to be viable.  The '205 lost the commercial race.
Mr Cray, who has been designing RISC architectures since the
dawn of time, is one of the winners.

>  It is the C language which is inadequate.  And there is a severe
>limit to what should be portable.
>> >I want to write
>> >	q,r = x/y;
>> Unfortunately, this already means something in C.
>
>What does it mean?

It means "evaluate the expression 'q', then the expression 'r =
x/y'.  The fact that 'q' is a variable doesn't mean anything.  It
is treated as an 'rvalue' (one that gives a result) rather than
as an 'lvalue' (where to put a result).  The comma operator is
extremely basic to the language.  It is probably a flaw in the
language design that it is programmer visible.  It is not a flaw
that i would suggest fixing.

>Would putting the q,r in parentheses or something else
>avoid the conflict?

Parenthesis will screw up something.  There is probably
a fix, but it won't be provable off the top of my head.

>> >At the present time and in the future, loads and stores must slow things
>> >down unless they can be overlapped.
>> 
>> Or optimized out.
>
>I consider a programmer quite inept who does not know what is temporary and
>what is not.

A compiler evaluating an expression generally produces all sorts
of temporary variables.  These are typically kept in registers,
but sometimes overflow - often to the stack.  On a machine like
the 205, with its near infinite register count, one would imagine
that there would never be register overflow.

>making this distinction and figure it out.  A compiler is fast, but does
>not compare in intelligence with a human imbecile.

Sure it compares.  The compiler is faster.  The compiler is
correct more often.  The human probably knows how to breath and
eat.  The compiler has no need for breathing or eating.  Of
course, there's the 'idiot savant', but i've never met one who
was actually much of an imbecile.

>The value of a compiler and language is ease of programming.  In this,
>notation and flexibility are extremely important.  If a mathematician
>finds notation missing, he invents it for his paper.  It may or may not
>be adopted by others, but that does not prevent people from reading his
>paper.

While i find such papers hard to read (especially since the
definition of the new notation syntax is seldom given), for
programs it is worse.  Even with the C preprocessor's limited
capabilities, one can write code that doesn't bear any
resemblence to C.  Maintanence of this code is nearly impossible.
Thus, sadly, notation flexibiltiy and maintainability are at odds.

>A simple example of the lack of desirability
>of C portability is the addition of two vectors.  The good coding of this
>depends on the costs of the *x++ in loading and storing and the use of
>index in loading and storing.  These depend both on the machine and the
>storage classes of the adresses.

The code sequence is:

void lvecadd(a, b, c, s) /* a = b + c, length s */
long *a; long *b; long *c; long s;
{
	do {
		*a++ = *b++ + *c++;
	} while (--s != 0);
}

or:

void lvecadd(a, b, c, s) /* a = b + c, length s */
long *a; long *b; long *c; long s;
{
	register long t;
	for (t = 0; i < s; t++)
		a[t] = b[t] + c[t];
}

A '205 C compiler should (doesn't but should) take either
piece of code and translate it into the instruction.

I've seen a C compiler which did better for the second example
than the first.  What was odd was that the target machine, a
68000, does better with the first algorithm.  Worse, the second
peice of code was effectively translated into the first, using
redundant temporary variables for the pointers.  Somehow, the
compiler thought that extra work had to take place for the first
example.  The point, though, is that the programmer visible
syntax need not bear any resemblence to the quality of the
produced code.

Portability has its costs - usually about 10 to 20% of the
optimum machine speed.  Compiler technology has been attempting
to narrow this.  However, it has enourmous benifits.  UNIX, being
somewhat portable, allows new architectures to become useful in
an extremely short time after manufacture (something like a
year).  The speed penalty that comes from UNIX not being designed
for the architecture is offset by the years of development that
it takes to create a new OS.  By that time, the architecture may
well be obsolete.  User applications are the same way.  The value
of using a portable language is more than just being able to use
code that was written on one machine on another.  It takes time
for programmers to become proficient in a language.  If you write
a new language for every program you write, no one will be able
to make heads or tails of what you've done.

dik@cwi.nl (Dik T. Winter) (07/08/89)

In article <5160018@hpfcdc.HP.COM> marc@hpfcdc.HP.COM (Marc `Play Ball!' Sabatella) writes:
 > > But I do not believe that C++ or Ada allows one to define
 > >symbols or symbol combinations as infix operators.
 > 
 > I don't know about C++, but Ada certainly does have this ability:
 > you simply define a function something like this:
 > 
 > 	function "\" (in x, y:integer) returns integer is begin ... end;
 > 
 > modulo my rusty syntax.

Disregarding the bad syntax; this is not allowed.  In Ada you can only
redefine the predefined operators (with some exceptions).  So a
declaration for "\" is not allowed.
-- 
dik t. winter, cwi, amsterdam, nederland
INTERNET   : dik@cwi.nl
BITNET/EARN: dik@mcvax

dik@cwi.nl (Dik T. Winter) (07/08/89)

Note also the reply why it is difficult to define syntax/semantics in
article <4909@ficc.uu.net> by peter@ficc.uu.net (Peter da Silva) and
the excellent explanation why MIPS does not provide a double width by
single width division in article <4016@bauhaus.NeXT.UUCP> by
chansen@NeXT.UUCP (Craig Hansen).  And I would also like to have
the double width operations directly visible, but I think it is more
difficult than Herman Rubin envisages.  In my opinion the gcc solution,
where you can use your own variables in asm statements, looks best.

A correction to the next statement:
In article <13970@haddock.ima.isc.com> suitti@haddock.ima.isc.com (Stephen Uitti) writes:
 > The code sequence is:
[a routine to add two vectors, using pointers]
 > or:
[an alternative]
 > A '205 C compiler should (doesn't but should) take either
 > piece of code and translate it into the instruction.
This is not true.  Because 'noalias' is out, the compiler has no knowledge
whether the sources overlap the destination.  So a lot more has to be done.
Unless the compiler is willing to do inlining, in which case it might (but
need not) have knowledge about overlap.

Another remark from the same article:
 > >I consider the 205 hardware the best designed vector hardware I have
 > >seen.
 > 
 > No real debate here.  The '205 was a real ambitious project.
 > Very, very difficult and costly to maintain, but real nice.
Some debate here (or simply, I do not agree).  However, the real problem
with the 205 is the abominable compiler.  Architecture is not really an
issue here; given a good compiler it would perform well.  Given the
compiler it has you have a heavy task to get acceptable performance.

On to the RISC vs. CISC debate:  how many of the 60000+ instructions
of the 205 do you think are ever used?  I know quite a lot that are
never used unless you use 'special calls', which is nothing more than
'asm' in C.

For discussions about the 205 hardware please follow up with a
different subject, or do it by mail.
-- 
dik t. winter, cwi, amsterdam, nederland
INTERNET   : dik@cwi.nl
BITNET/EARN: dik@mcvax

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (07/08/89)

In article <1395@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin)
writes his usual continuing diatribe against modern (or, in the case
of C, not-so-modern) programming language designers.

Herman wants a language that is both notationally flexible enough to
allow him to use whatever notation is comfortable for him, and
sufficiently smart that he can write code that obviously maps 1-1 onto
machine hardware for the machine he's writing it for.

Since modern programming language designers are more concerned with
features like portability, maintainability and reusability (and the
ability to say *ability :-), they tend to ignore the things he wants.
Notational flexibility leads to nearly unreadable code, and incredible
support libraries, the antithesis of readability and maintainability.
The ability to write code specific to a machine architechture is
obviously antagonistic to the goal of portability.

Herman isn't the only person running around claiming some major area
of CS is going in the wrong direction. He isn't even the only one to
argue about it a lot, and do nothing to prove his point. He may even
be right.

However, flaming about it on USENet isn't going to do anything other
than make AT&T a lot of money.

Herman, you need to do three things. 1) Write or find a language that
is what you want. 2) Arrange to give it, along with enough
documentation for it to be useable, to anyone who wants it. 3) Write a
paper acceptable to a refereed journal (or SNot) describing the
language, and why it's superior to everything else available.

I predict that you'll be roundly ignored, as what you want is really
little more than a flexible template macro processor on top of an
assembler. Spiffy assemblers have been proposed before (Johnson at
Bell Labs wrote one; Whitesmith sold one with their C compilers), and
were roundly ignored.

	<mike
--
Cheeseburger in paradise                                Mike Meyer
Making the best of every virtue and vice                mwm@berkeley.edu
Worth every damn bit of sacrifice                       ucbvax!mwm
To get a cheeseburger in paradise                       mwm@ucbjade.BITNET

cik@l.cc.purdue.edu (Herman Rubin) (07/08/89)

In article <4909@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:
> In article <1388@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes:
> > For example, on a machine in which there is division yielding a quotient
> > and a remainder, I want to write
> 
> > 	q,r = x/y;
> 
> (1) What does this do when no such operation exists?

What does q = x/y; get you if division does not exist?  There are such
machines.  Would it be totally rash to suggest that the reason that this
does not exist on more machines may be related to the fact that it does
not exist in the languages?

> (2) How does this fit in with the rest of the expression syntax?

I do not see the problem here.  The fact that there are a fair number
of people now using it is a good reason to keep it.  If you mean, how
does it fit into compound expressions, there are ways of doing it, but
I am not sure that I care.  If I have to give them up, but can specify
local temporaries, I will.

> (3) Get a good optimiser and say:
> 	q = x/y;
> 	r = x%y;

Does your language even have long long?  The same remark holds about
temporaries.  And if I have to put them in adjacent registers because
of the hardware, I will.

> (4) Is it obvious which is the quotient and which is the remainder
>     when you have something like:
> 	tens,relx = muscle0.fiber/potential;

All languages have conventions.  I find many of them more annoying
than this problem.

> (5) What if x or y contain other operations that could require a
>     quotient or remainder?

If it is necessary to break a complex operation into simple parts, do it.
This does not apply to the original problem, as the operation wanted is,
on many machines, a single machine instruction.  If the machine can do
it in one instruction, I demand that I can put it in the language as one
statement.  I do not expect everything to be portable.

> (6) What does this mean:
> 	q,r,s = x/y/z;

I do not know.  I am not even sure what a = x/y/z; means.  I would not
use that without parentheses.  I suspect that what is wanted is a pair
of statements, with an intermediate result a declared temporary.

> (7) What does this sort of micro-optimisation gain you? Except in a
>     tight loop, very little. Since you're intending to be machine-
>     specific anyway, why not squirrel that loop away in an assembly
>     routine?

Notation can be very important.  I consider the introduction of algebraic
symbols by Diophantus a major contribution.  My complaint about assembly
language (not machine language) is that it is written in a thoroughly
obfuscated notation.  But machine language needs an "alphabet."

I am perfectly willing to write in what I call a HLL machine language.
Given a decent macro processor, in which the syntax, including the
macro name, is arbitrary, I would write that.  This is really what
a compiler is; a macro processor, possibly with an optimizer added.
Some "optimizers" do little more than add to the macro processor.

So what I am saying is that if the machine can do it, I want a reasonable
way to include it.  I do not consider the current assemblers reasonable,
and I have pointed out some of the reasons why.
> Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
> Business: peter@ficc.uu.net, +1 713 274 5180. | "WHAT HAPPENED TO ALL
> Personal: peter@sugar.hackercorp.com.   `-_-' |  THE WOMEN IN TEXAS?"
> Quote: Have you hugged your wolf today?  'U`  |  -- ACS1W@jane.uh.edu (meesh)


-- 
Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907
Phone: (317)494-6054
hrubin@l.cc.purdue.edu (Internet, bitnet, UUCP)

hascall@atanasoff.cs.iastate.edu (John Hascall) (07/09/89)

In article <1399@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>In article <4909@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:

  [... back and forth about expressions with N return values (N >= 1) ...]
 
>I am perfectly willing to write in what I call a HLL machine language.
>Given a decent macro processor, in which the syntax, including the
>macro name, is arbitrary, I would write that.  This is really what
>a compiler is; a macro processor, possibly with an optimizer added.
 
 
 Well, there's always BLISS!    :-)


John "just causing trouble" Hascall

p.s.,  I do have to agree with the sentiment that computer languages (well,
       actually the entire computer industry) have tended to have a rather
       narrow view of the problems the rest of the world would like to solve
       and the methods they would like to use.
       

stuart@bms-at.UUCP (Stuart Gathman) (07/11/89)

[ previous poster wants "q,r = x/y" to assign quotient to q, remainder to r ]

Even on fairly stupid compilers,

	q = x / y;
	r = x % y;

results in what you want (unless x & y have side effects - in that case assign
to temporaries).  In the absence of branches, even simple CSE is amazingly good.
-- 
Stuart D. Gathman	<stuart@bms-at.uucp>
			<..!{vrdxhq|daitc}!bms-at!stuart>

jeff@aiai.ed.ac.uk (Jeff Dalton) (07/22/89)

In article <1395@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes:
>In article <13961@haddock.ima.isc.com>, suitti@haddock.ima.isc.com (Stephen Uitti) writes:
>> LISP does not actually pass whole lists around - it uses pointers
>> and linked lists.
>
>And this is the reason that production programs and library subroutines
>should not be written in Lisp.

Why?  Because Lisp uses pointers?

Some of the things C library procedures do are much worse than that.

 >But it is possible to get much done efficiently.  This should be done
 >by enabling those who can see how to do things to do them and to
 >communicate that to others.  Anything can be done on a universal
 >Turing machine, but I am not willing to wait a month for it to
 >multiply two 10-digit numbers by reducing everything to successor.

I'm not sure if this is still supposed to be about Lisp.
If so, you should note that Lisp has more than one data type.