Xref: utzoo comp.arch:10528 comp.lang.misc:3044 Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!mailrus!tut.cis.ohio-state.edu!husc6!purdue!mentor.cc.purdue.edu!l.cc.purdue.edu!cik From: cik@l.cc.purdue.edu (Herman Rubin) Newsgroups: comp.arch,comp.lang.misc Subject: Re: Double Width Integer Multiplication and Division Summary: Notation and syntax are very important for programming. Message-ID: <1395@l.cc.purdue.edu> Date: 7 Jul 89 13:45:16 GMT References: <57125@linus.UUCP> <1989Jun24.230056.27774@utzoo.uucp> <13961@haddock.ima.isc.com> Followup-To: comp.arch,comp.lang.misc Organization: Purdue University Statistics Department Lines: 216 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)