dca@kesmai.COM (David C. Albrecht) (09/29/87)
I would be interested in some other people's input on this. One of our latest products where I work is a flight simulator. We do alot of integer arithmetic. The original target of the program was the MAC it has since been ported to the Amiga and is now being ported to the ST. Okay, note that these are all 68K machines. In trying to squeeze more speed out of it on the Amiga I noticed a good many multiplys were 16x16=32 (which is supported in hardware on the 68000) while it was currently using 32x32=32 (which is not). In attempting to get the MULS operation I made the variables 16bit in size and coded the expression thusly: ((long) (x * y)) It is a bit greasy but it was the only way I could think of to get the proper result. On the Amiga using Lattice 3.10 it worked ducky. Recently we moved the code back to the MAC which is using Counsulair (sp?) and that also seems to work. On the ST using Mark Williams we were not so lucky. They actually explicitly sign extend the result throwing away the upper 16bits. We assumed that they did so because their compiler was not smart enough to recognize that it already had a long result which it could just use. After some communication with them they claimed that the phrase on pg184 in K&R which says that an expression with two ints should produce an int (their ints are 16 bits) REQUIRE that they sign extend or they will fail some of their commercial customers acceptance suites. Personally I think they are full of it. Does anyone know of a commercial test suite that checks to make sure that y = x * x where x is a 16 bit int and y is long (32 bits) produces garbage instead of the proper result? Seems like just the kind of thing I would want in my software. Why have good numbers when I could have garbage? Seriously, I can understand their compiler being a little simple and not producing the result I desire because it isn't sharp enough to realise that the result of a MULS is either 16 bits or 32 bits depending on what you want. I find it extremely unlikely that this behavior is required, however. If someone out there could point out to me the error of my ways and why an acceptance suite would test this or just relate first hand experience with a suite that does test this I would be most interested. David Albrecht
rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (10/12/87)
> the phrase on pg184 in K&R which says that an expression with two ints > should produce an int (their ints are 16 bits) REQUIRE that they sign > extend or they will fail some of their commercial customers acceptance > suites. Personally I think they are full of it. Actually, no, they are quite correct. If sizeof(int)==2, and int x,y ; and long z; and sizeof(long)==4, then z = x * y should generate muls d1,d0 ext.l d0 according to K&R; the result *must be* of type int (2 bytes) and therefore it must be coerced into a long. The correct way to do this is z = x * (long)y ; which usually generates ext.l d0 ext.l d1 ; both operands must be long jsr .muls but smart compilers (like Manx 3.4) will generate the equivalent muls d1,d0 because the two are exactly idential. (Similarly, idiotic compilers will generate, for char *p, *q ; if (*p==*q) move.b (a0),d0 ext.w d0 move.b (a1),d1 ext.w d1 cmp.w d0,d1 because theoretically, all operations are performed with at least int accuracy, but smart compilers will generate cmp.b (a0),(a1) you would be surprised how many generate the former! Try it.) > Does anyone know of a commercial test suite that checks to make sure that > y = x * x where x is a 16 bit int and y is long (32 bits) produces garbage > instead of the proper result? Seems like just the kind of thing I would > want in my software. Why have good numbers when I could have garbage? The rules for C type coercion are well laid down and fairly unambiguous. Violating them so this one case works is not a good idea. Specifically, int x, y; long z ; z = x * y ; /* is not exactly equivalent to */ z = (long)x * (long)y ; /* but */ z = x * (long)y ; /* is equivalent to */ z = (long)x * (long)y ; and the lone muls will do the latter, but not the former, if the compiler is smart enough. And it doesn't take a much smarter compiler to handle x * (long)y correctly. -tom
ark@alice.UUCP (10/13/87)
In article <141@kesmai.COM>, dca@kesmai.UUCP writes: > Does anyone know of a commercial test suite that checks to make sure that > y = x * x where x is a 16 bit int and y is long (32 bits) produces garbage > instead of the proper result? Garbage *IS* the proper result. If x is a 16-bit number, x*x is also a 16-bit number. The result of overflow is undefined. If you want the 32-bit product of x and x on a machine with 32-bit longs, the way to write it is (long) x * (long) x or x * (long) x or (long) x * x while is evaluated as ((long) x) * x You can then flame at your compiler vendor for not being smart enough to generate a single instruction for the expression (in fact, some compilers are smart enough).
rick@oresoft.UUCP (Rick Lahrson) (10/13/87)
In article <141@kesmai.COM> dca@kesmai.COM (David C. Albrecht) writes: > ... In attempting to get the MULS operation >I made the variables 16bit in size and coded the expression thusly: > >((long) (x * y)) > >It is a bit greasy but it was the only way I could think of to get >the proper result. On the Amiga using Lattice 3.10 it worked ducky. >Recently we moved the code back to the MAC which is using Counsulair (sp?) >and that also seems to work. On the ST using Mark Williams we were not >so lucky. They actually explicitly sign extend the result throwing away >the upper 16bits. We assumed that they did so because their compiler >was not smart enough to recognize that it already had a long result which >it could just use. After some communication with them they claimed that >the phrase on pg184 in K&R which says that an expression with two ints >should produce an int (their ints are 16 bits) REQUIRE that they sign >extend or they will fail some of their commercial customers acceptance >suites. Personally I think they are full of it. I think it's more of an implementation decision. C tries to fill two sometimes conflicting niches. On the one hand, it lets the programmer get down to the nitty gritty, by making the machine very accessible. On the other hand, it needs to be as portable as possible. But porta- bility for arithmetic requires that you feign ignorance of the actual capabilities of the machine you're on, and use only capabilities that all machines/implementations can be expected to have. For example, if you write: a = ((long) (b * c)) / d; where a, b, c, and d are ints, on a 68K you might expect arithmetically correct answers for any values of b and c. But what if an int were 32 bits? In that case, a long and an int would be the same size, the multiplication would not be carried to double precision, and some values of b and c would cause an overflow. So for portability reasons, the "common denomimator" among all implementations on all machines seems to be that the result of a multiplication (1) will contain no fewer bits than there are in the larger factor (let's hope!); and (2) will contain no more bits than there are in the larger factor (because many machines/ implementations simply don't provide that capability). I don't have a C validation suite to look at, and the above definition of a likely compromise is just my best guess, but I'll bet the compiler that holds the precision to the size of the operands is the one that the validation suite will like. In my copy of K&R, the referenced phrase on p 184 just happens to be ... The Bottom Line! 8-) -- Rick Lahrson ...tektronix!oresoft!rick Disclaimer: If I ever speak for anyone but me, I'll warn you in advance.
higgin@cbmvax.UUCP (Paul Higginbottom SALES) (10/14/87)
in article <141@kesmai.COM>, dca@kesmai.COM (David C. Albrecht) says: > Xref: cbmvax comp.lang.c:4799 comp.sys.atari.st:5522 comp.sys.amiga:9125 > > I would be interested in some other people's input on this. > ...I noticed a good many multiplys were 16x16=32 (which is > supported in hardware on the 68000) while it was currently using > 32x32=32 (which is not). In attempting to get the MULS operation > I made the variables 16bit in size and coded the expression thusly: > > ((long) (x * y)) > > It is a bit greasy but it was the only way I could think of to get > the proper result. On the Amiga using Lattice 3.10 it worked ducky. > Recently we moved the code back to the MAC which is using Counsulair (sp?) > and that also seems to work. On the ST using Mark Williams we were not > so lucky. They actually explicitly sign extend the result throwing away > the upper 16bits. We assumed that they did so because their compiler > was not smart enough to recognize that it already had a long result which > it could just use. After some communication with them they claimed that > the phrase on pg184 in K&R which says that an expression with two ints > should produce an int (their ints are 16 bits) REQUIRE that they sign > extend or they will fail some of their commercial customers acceptance > suites. Personally I think they are full of it. Personally (and knowing the guys at MWC), I bet they're right. Second, your expression '((long) (x * y))' should not do as you say because the cast is performed AFTER the expression is evaluated, so '(x * y)' is 16bits x 16bits, which is not supposed to be guaranteed to generate 32 bits, but instead will generate another int (16 bits), the overflow having probably been lost, or is at least undefined, and THEN the result is cast to a long, and to make the sign extension work properly, bit 15 will be extended through bits 16-31. > > Does anyone know of a commercial test suite that checks to make sure that > y = x * x where x is a 16 bit int and y is long (32 bits) produces garbage > instead of the proper result? ^^^^^^ This word is important. I think the result of an OVERFLOWED 16 bit quantity is undefined. > David Albrecht Paul Higginbottom
mhatter@pnet02.CTS.COM (Patrick E. Hughes) (10/15/87)
In addition to a small letter I sent to the author of the original message that started this whole mess, I might suggest one thing if you plan on porting many C programs: Don't Use Ints Use char, use long, use float, and since they don't change size you're always set. Ints, as I've seen, are consistently inconsistent. UUCP: {hplabs!hp-sdd!crash, ihnp4!scgvaxd!cadovax}!gryphon!pnet02!mhatter INET: mhatter@pnet02.CTS.COM
crowl@cs.rochester.edu (Lawrence Crowl) (10/16/87)
In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM (Patrick E. Hughes) writes: >I might suggest one thing if you plan on porting many C programs: Don't Use >Ints. Use char, use long, use float, and since they don't change size you're >always set. Ints, as I've seen, are consistently inconsistent. NO! Char, short, and long do change size. The only thing you can rely on is that sizeof char <= sizeof short <= sizeof int <= sizeof long. If you want portable programs, DO NOT USE BASIC TYPES. At the top of the program, define a set of typedefs from program specific types to the basic types. For example: typedef char autos_t ; /* for number of automobiles owned by a person */ /* expected range 0 .. 20 */ typedef int potatoes_t ; /* for number of potatoes eaten by a city */ /* expected range 0 .. 80,000,000 */ Because the size of every program type can be changed in exactly one place in the source, this approach provides two major advantages. First, it is portable from one machine to another, and second, it allows the program to adapt to changing needs or improper design decisions. -- Lawrence Crowl 716-275-9499 University of Rochester crowl@cs.rochester.edu Computer Science Department ...!{allegra,decvax,rutgers}!rochester!crowl Rochester, New York, 14627
mlandau@bbn.com (Matt Landau) (10/16/87)
In comp.lang.c (<1912@gryphon.CTS.COM>), mhatter@pnet02.CTS.COM (Patrick E. Hughes) writes: >In addition to a small letter I sent to the author of the original message >that started this whole mess, I might suggest one thing if you plan on porting >many C programs: Don't Use Ints > >Use char, use long, use float, and since they don't change size you're always >set. Don's change size, eh? You want signed or unsigned chars? And how many bits are there in a char anyway? Eight? Nine? Thirteen? The language doesn't specify anything about chars, or longs (except that sizeof(long) >= sizeof(int), which isn't much help), or much of anything else where the size and representation of arithmetic types are concerned. If you're concerned about being portable, use typedefs. I generally try to typedef signed and unsigned types of 8, 16, and 32 bits, and some kind of short and long flaoting point types. For most machines, the integer types work out to: typedef unsigned char UINT8; typedef unsigned char BYTE; /* I like BYTE, so what? */ typedef unsigned short UINT16; typedef unsigned int UINT32; typedef char INT8; typedef short INT16; typedef int INT32; though on Intel-based PC's and other perverse hardware, things change a bit. Note that these are *minimum* number of bits, not *exact* number of bits; Anything that requires exact sizes is probably going to need its own set of application-specific typedefs anyway. The point is, the code only uses "int" or "char" when the details don't matter and it's important to get the "best" performance (which one assumes you get by using the "natural size" integer -- that's what "int" in C *means*). If it matters how many bits something is, using the typedefs insures that the code is portable to any machine for which all of the appropriate types can be defined. -- Matt Landau Waiting for a flash of enlightenment mlandau@bbn.com in all this blood and thunder
gwyn@brl-smoke.ARPA (Doug Gwyn ) (10/19/87)
In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM (Patrick E. Hughes) writes: >Don't Use Ints Nonsense! Not only can you not avoid (int)s, which are the inherent type of several things in the language, but (int) is usually the fastest data type with 16 or more bits in any implementation. If you just need to hold a modest count, (int) is the best choice. Also note that many library functions require (int) arguments.
andy@cbmvax.UUCP (Andy Finkel) (10/20/87)
In article <3294@sol.ARPA> crowl@cs.rochester.edu (Lawrence Crowl) writes: >In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM >(Patrick E. Hughes) writes: >>I might suggest one thing if you plan on porting many C programs: Don't Use >NO! Char, short, and long do change size. The only thing you can rely on is >that sizeof char <= sizeof short <= sizeof int <= sizeof long. If you want >portable programs, DO NOT USE BASIC TYPES. At the top of the program, define a We at the Banzai Institute always use typedefs :-) Ours are stored in the include file exec/types.h To maintain readability, however, the names were a bit a bit boring, ie LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID. andy -- andy finkel {ihnp4|seismo|allegra}!cbmvax!andy Commodore-Amiga, Inc. "Interfere? Of course we'll interfere. Always do what you're best at, I always say." Any expressed opinions are mine; but feel free to share. I disclaim all responsibilities, all shapes, all sizes, all colors.
jimm@mitsumi.UUCP (Jim Mackraz) (10/20/87)
In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes: )In article <3294@sol.ARPA> crowl@cs.rochester.edu (Lawrence Crowl) writes: )>In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM )>(Patrick E. Hughes) writes: )>>I might suggest one thing if you plan on porting many C programs: Don't Use )>NO! Char, short, and long do change size. The only thing you can rely on is )>that sizeof char <= sizeof short <= sizeof int <= sizeof long. If you want )>portable programs, DO NOT USE BASIC TYPES. At the top of the program, define a ) )We at the Banzai Institute always use typedefs :-) )Ours are stored in the include file exec/types.h )To maintain readability, however, the names were a bit a bit boring, ie )LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID. )andy finkel {ihnp4|seismo|allegra}!cbmvax!andy Well, one qualification on this business is that sometimes you want Mr. Compiler to choose its most efficient type. For example, in Intuition, there was a large number of cases where SHORT was used in loop counters, and other places where a small counting number was needed. There appeared to be explicit sign extension operation frequently applied to these SHORTs. When many SHORTS were converted to 'ints', the resulting code was significantly smaller (note: significant to people who changed the name "rawinput" to "ri" because we needed the 6 bytes. Yea, significant to people who waited from Jul 31 to Aug 1 for the big build because that second digit in the date string, multiplied by the number of libraries, ...). It also broke where a pointer to an 'int' was passed to a program expecting a pointer to a SHORT. But *sometimes*, there are *some* reasons for saying 'int' instead of either LONG or SHORT. jimm -- Jim Mackraz Mitsumi Technology, Inc. 408/980-5422 {amiga,pyramid}!mitsumi!jimm
MAXHAM@RICE.BITNET (Mark Maxham) (10/20/87)
But the 68000 MULS and MULU commands multiply two sixteen bit words into a 32 bit longword. Thus they are defined. Is the question how C translates from multiplicitive expressions into actual machine instructions? Mark Maxham maxham@icsa.rice.edu
ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (10/21/87)
In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes: >We at the Banzai Institute always use typedefs :-) >To maintain readability, however, the names were a bit a bit boring, ie >LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID. > ^^^^ I think your VOID definition is broken. In the file exec/interrupts.h is the structure: struct Interrupt { struct Node is_Node; APTR is_Data; VOID (*is_Code)(); }; Then, later on, when I try and do this: foo () { extern long bar(); interrupt.is_Code = (VOID) bar; } ...my compiler throws up. Something about an invalid use of the 'void' declaration. I have Manx 3.4b. I know, it's probably my fault, so I don't cast it and live with the warning message.... _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ Leo L. Schwab -- The Guy in The Cape ihnp4!ptsfa -\ \_ -_ Recumbent Bikes: dual ---> !{well,unicom}!ewhac O----^o The Only Way To Fly. hplabs / (pronounced "AE-wack") "Although there are technical differences between the quality of images created on the Amiga and on our system, we feel that viewers could be misled to believe otherwise, even with your disclaimers to the contrary." -- Ralph J. Guggenheim, Pixar
andy@cbmvax.UUCP (Andy Finkel) (10/21/87)
In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes: >In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes: > I think your VOID definition is broken. In the file >exec/interrupts.h is the structure: Interesting...in our exec/types.h file we have a #define VOID void statement, to put the onus of handling this onto the compiler :-) typedefing VOID as void caused strangeness with Greenhills C. Well, something else to look into, I guess. -- andy finkel {ihnp4|seismo|allegra}!cbmvax!andy Commodore-Amiga, Inc. "Interfere? Of course we'll interfere. Always do what you're best at, I always say." Any expressed opinions are mine; but feel free to share. I disclaim all responsibilities, all shapes, all sizes, all colors.
grr@cbmvax.UUCP (George Robbins) (10/21/87)
In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes: > In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes: > >We at the Banzai Institute always use typedefs :-) > >To maintain readability, however, the names were a bit a bit boring, ie > >LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID. > > ^^^^ > I think your VOID definition is broken. In the file > exec/interrupts.h is the structure: > > Then, later on, when I try and do this: ... > foo () > { > extern long bar(); > interrupt.is_Code = (VOID) bar; > } > > ...my compiler throws up. Something about an invalid use of the > 'void' declaration. I have Manx 3.4b. Wait a minute - there are two void concepts: 1) routines that don't return anything, 2) pointers to things of indeterminate nature. In you expample, it looks like you are dealing with a long, rather than a pointer - try (yeech) = (VOID *) bar; or why not simply declare bar() as VOID *bar(); if this is the only way you are using it? Me, I'm just a hardware guy this incarnation... -- George Robbins - now working for, uucp: {ihnp4|rutgers|allegra}!cbmvax!grr but no way officially representing arpa: out to lunch... Commodore, Engineering Department fone: 215-431-9255 (only by moonlite)
starner@ihlpg.ATT.COM (Guy Starner) (10/23/87)
In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes: > ... Then, later on, when I try and do this: > ... > interrupt.is_Code = (VOID) bar; > > ...my compiler throws up. Shouldn't this be: interrupt.is_code = (VOID (*)()) bar; That is, cast bar to a pointer to a function returning void. Guy Starner AT&T Bell Laboratories ...!ihnp4!ixlpn!starner -- Guy Starner IHP 2F-522, 416-7396 ixlpn!starner
cik@l.cc.purdue.edu (Herman Rubin) (10/24/87)
In article <146MAXHAM@RICE>, MAXHAM@RICE.BITNET (Mark Maxham) writes: > But the 68000 MULS and MULU commands multiply two sixteen bit words > into a 32 bit longword. Thus they are defined. Is the question > how C translates from multiplicitive expressions into actual machine > instructions? > > Mark Maxham maxham@icsa.rice.edu > A general problem with HLL's is that they do not have the necessary flexibility to handle situations like this. I do not know of any language which has in its operation list an operation to multiply two 16 bit object and get a 32 bit object. (Note: I am using the term "object" because what is called a word, longword, etc., differs from machine to machine.) On many machines, this would have to be done by the portable method of converting the 16 bit objects to 32 bits, but the possessor of a machine which can do the operation directly should not have to go to such lengths to achieve the results. How about the related problem of multiplying two 32 bit objects and getting a 64 bit object? Other than inserting assembler instructions, which may involve such problems as not knowing where the (expletive deleted) compiler has decided to locate the objects, I see no way to do this in any HLL. I know of no way to tell the compiler that here is an operation with a given syntax, and the compiler should put it in its set of operations. If the syntax is different from other syntaxes for that operator, the compiler should perform the overloading. It is clear that the languages need more flexibility and that the gurus who claim that they have the solutions are wrong. -- Herman Rubin, Dept. of Statistics, Purdue Univ., West Lafayette IN47907 Phone: (317)494-6054 hrubin@l.cc.purdue.edu (ARPA or UUCP) or hrubin@purccvm.bitnet
rico@oscvax.UUCP (10/24/87)
In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes: > > I think your VOID definition is broken. In the file >exec/interrupts.h is the structure: > >struct Interrupt { > struct Node is_Node; > APTR is_Data; > VOID (*is_Code)(); >}; > > Then, later on, when I try and do this: > >foo () >{ > extern long bar(); > > interrupt.is_Code = (VOID) bar; >} Sorry Leo, I think you missed it... it should be interrupt.is_Code = (VOID (*)()) bar; You want to cast bar into a pointer to a function returning VOID you *don't* want to cast bar into a VOID. Casting something to VOID means "throw it away". Having thrown it away you can't assign it to interrupt.is_Code. The only time you ever (well I can't think of any other reason right now anyways) want to cast something to VOID (as opposed to a pointer to VOID or pointer to function returning VOID or anything like that) is if you want to discard the return value of some function. e.g. (VOID)gets(s); /* throw away the return value */ /* this keeps lint happy */ -Rico -- [NSA food: terrorist, cryptography, DES, drugs, CIA, secret, decode] [CSIS food: supermailbox, tuna, fiberglass coffins, Mirabel, microfiche] [Cat food: Nine Lives, Cat Chow, Meow Mix, Crave]
firth@sei.cmu.edu (Robert Firth) (10/27/87)
In article <593@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes: [discussion of 16*16=>32] >A general problem with HLL's is that they do not have the necessary >flexibility to handle situations like this. I do not know of any language >which has in its operation list an operation to multiply two 16 bit object >and get a 32 bit object. The language RTL/2 has exactly this feature; it has versions of "*" that can multiply integers to give long ints or fractions to give long fracs. A more modern language that recognises this problem is Ada, which has explicit features for fixed-point multiplication with double-length result (hidden in RM 3.5.9,3.5.10), and indeed for "rule-of-three" operations (multiply to double length; divide back to single length). These are defined in fairly general terms, and so can be mapped onto a variety of multiple-length machine types, not just 16 and 32. The systems language BCPL has an extension that provides the rule-of-three primitive (called MULDIV), but for integers only.
mpl@sfsup.UUCP (M.P.Lindner) (10/27/87)
In article <2565@cbmvax.UUCP>, grr@cbmvax.UUCP writes: > In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes: > > In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes: > > >We at the Banzai Institute always use typedefs :-) > > >To maintain readability, however, the names were a bit a bit boring, ie > > >LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID. Here's the final word on several offshoots to the original article I've been reading. 1. > > I think your VOID definition is broken. In the file > > exec/interrupts.h is the structure: > > > > interrupt.is_Code = (VOID) bar; What you *should* be doing is interrupt.is_Code = (VOID (*)()) bar; 2. as for the person doing int x; (long) (x * x) What *you* should be doing is ((long) x * x) since you can't get back the 16 bits lost after you do the multiply as a 16 bit quantity. 3. as for the people who say "Never use the basic types", I say the following: 1. use "char" to mean a character or a byte (guaranteed in K&R) 2. use short for a small integer 3. use int where the size doesn't matter 4. use long where you need a long (ie in interfacing to the OS, etc.) 5. use pointers with care 6. use void where you mean void (either the compiler handles it or it doesn't - if it does, great, if it doesn't, try "cc -Dvoid=int" but don't go changint the input language because you have a bad compiler. 7. NEVER NEVER NEVER! use LONG, ULONG, VOID, etc. if you're using ULONG because you want an unsigned 32 bit integer try using typedef unsigned long uint32; typedef long int32; so someone can try to figure out what bizzare thing you were trying to do. Mike Lindner attunix!mpl
crowl@cs.rochester.edu (Lawrence Crowl) (10/27/87)
In article <2262@sfsup.UUCP> mpl@sfsup.UUCP (M.P.Lindner) writes: >3. as for the people who say "Never use the basic types", I say the following: > 1. use "char" to mean a character or a byte (guaranteed in K&R) Use char to mean a character. Use "typedef char applicationtype" when the best implementation for the intended use happens to be a char on your machine. My six bit char may not give the range you assumed because of your chars are twelve bits. > 2. use short for a small integer Use "typedef short applicationtype" when the best implementation for the intended use happens to be a short on your machine. My short may be longer than your short. This way I only have to change the implementation in one place. > 3. use int where the size doesn't matter Use "typedef int applicationtype" when the implementation for the intended use does not matter significantly. Let's hope my ints are at least as large as you assume. > 4. use long where you need a long (ie in interfacing to the OS, etc.) Use a crowbar where you need a crowbar? Use "typedef long systemtype" when the implementation for the system type is a long. When porting, changing the types passed to system routines in one place can reduce hassle considerably. > 5. use pointers with care Amen. > 6. use void where you mean void (either the compiler handles it or > it doesn't - if it does, great, if it doesn't, try "cc -Dvoid=int" > but don't go changing the input language because you have a bad > compiler. Agreed. > 7. NEVER NEVER NEVER! use LONG, ULONG, VOID, etc. > if you're using ULONG because you want an unsigned 32 bit integer > try using > typedef unsigned long uint32; > typedef long int32; > so someone can try to figure out what bizzare thing you were trying > to do. Use "typedef BASIC_TYPE APPLICATION_TYPE /* required range is a..b */". This documents the program's needs and allows people porting the program to identify exactly what changes need to be made. -- Lawrence Crowl 716-275-9499 University of Rochester crowl@cs.rochester.edu Computer Science Department ...!{allegra,decvax,rutgers}!rochester!crowl Rochester, New York, 14627
mac3n@babbage.UUCP (10/27/87)
In article <593@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: > A general problem with HLL's is that they do not have the necessary > flexibility to handle situations like this. I do not know of any language > which has in its operation list an operation to multiply two 16 bit object > and get a 32 bit object. In, e.g., Ada the overloading operators allow one to extend "*" for use with two "16 bit" objects when the context calls for a "32 bit" object. Ada is fairly unusual in allowing overload resolution based on context, a feature that adds considerable complexity to the compiler. > I know > of no way to tell the compiler that here is an operation with a given syntax, > and the compiler should put it in its set of operations. The usual way to extend the set of operations in a language is with procedures. Many languages are compatible with machine-language procedures. Some languages allow inline procedues. Some even allow inline assembler. If you really want that much control over the code generated, perhaps you should write your own compiler. There are several systems which construct code generators from a set of instructions and their semantics. Automatic code generation generation is still pretty new. > It is clear that the languages need more flexibility > and that the gurus who claim that they have the solutions are wrong. Few Gurus claim that they have the perfect solutions. Merely adequate.
rat@circle.UUCP (10/28/87)
In a previous message, Herman Rubin, Purdue University, sez: >.... I do not know of any language which has in its operation list an >operation to multiply two 16 bit object and get a 32 bit object. ... -- and then goes on to say -- >.. How about the related problem of multiplying two 32 bit objects and >getting a 64 bit object? ... Forth is has an operator M* (pronounced "M-star" for all you "pronunciation" types) which takes two 16-bit values and returns their 32-bit product. I would conjecture that after the smoke clears on a possible 32-bit based Forth standard, that M* could change from a 16x16=32 to a 32x32=64 bit multiply. No doubt someone will say "Forth, ugh!". All I can say is, pooh on you! :-) "Off with her head!" -- ::: David Douthitt ::: Madison, Wisc ::: uucp mail: ...!uwvax!geowhiz!uwspan!circle!rat fidonet mail: 121/1
bpendlet@esunix.UUCP (10/28/87)
in article <593@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) says: > Xref: esunix comp.lang.c:4825 comp.misc:1454 > > In article <146MAXHAM@RICE>, MAXHAM@RICE.BITNET (Mark Maxham) writes: >> But the 68000 MULS and MULU commands multiply two sixteen bit words >> into a 32 bit longword. Thus they are defined. Is the question >> how C translates from multiplicitive expressions into actual machine >> instructions? >> >> Mark Maxham maxham@icsa.rice.edu >> > > A general problem with HLL's is that they do not have the necessary > flexibility to handle situations like this. I do not know of any language > which has in its operation list an operation to multiply two 16 bit object > and get a 32 bit object. Whether or not you consider forth to be a high level language is a matter of taste. But, in the last version of the forth standard that I read ( quite old actually ) there was an operator named */ that multiplies two 16 bit ints giving a 32 bit int and then divides by a 16 bit int to give a 16 bit result. not quite what you asked for, but very close. > I know > of no way to tell the compiler that here is an operation with a given syntax, ^^^^^^ I think the term you are looking for here is "signature", the name of the operator, plus the number of arguments, the type of the arguments, the order of the arguments and type of the result. > and the compiler should put it in its set of operations. If the syntax is > different from other syntaxes for that operator, the compiler should perform > the overloading. It is clear that the languages need more flexibility > and that the gurus who claim that they have the solutions are wrong. Operator overloading has been implemented in many compilers. It is pretty trivial to implement. I know, I've implemented it. If this is meant as a criticism of C, well there is a lot to criticise about C. But, one of the hallmarks of C is its lack of features, especially syntactic features. C is rather elegant in its syntactic simplicity. If you are looking for a modern language with a lot of syntactic features and a lot of flexibility, try reading a good book on ADA. If you want flexibility with a minimum of syntose, look a LISP. Programming language syntax is a cancer. The bigger it is, the harder it is to live with. Bob P. -- Bob Pendleton @ Evans & Sutherland UUCP Address: {decvax,ucbvax,ihnp4,allegra}!decwrl!esunix!bpendlet Alternate: {ihnp4,seismo}!utah-cs!utah-gr!uplherc!esunix!bpendlet I am solely responsible for what I say.
henry@utzoo.UUCP (Henry Spencer) (10/28/87)
> ... I do not know of any language > which has in its operation list an operation to multiply two 16 bit object > and get a 32 bit object... As has been said before, in C on a machine where shorts are 16 bits and longs 32, "(long)shortvar * (long)shortvar" does *exactly* this, assuming that the compiler is smart enough to notice that it can do the casts as part of the multiplication. With the bonus that it works, although more slowly, even if the compiler doesn't notice. > ... How about the related problem of multiplying two 32 bit objects and > getting a 64 bit object? ... Given suitable data types (some 32-bit-machine C compilers have a "long long" type for 64-bit integers), the same comment applies. -- PS/2: Yesterday's hardware today. | Henry Spencer @ U of Toronto Zoology OS/2: Yesterday's software tomorrow. | {allegra,ihnp4,decvax,utai}!utzoo!henry
toma@tekgvs.TEK.COM (Tom Almy) (10/28/87)
(I don't have the original article) In article <593@l.cc.purdue.edu> cik@l.cc.purdue.edu (Herman Rubin) writes: >A general problem with HLL's is that they do not have the necessary >flexibility to handle situations like this. I do not know of any language >which has in its operation list an operation to multiply two 16 bit object >and get a 32 bit object. Forth does. It also provides a 32 bit by 16 bit divide operation, a multiply divide function (a*b/c) combining these two for scaled integer arithmetic, and a divide function returning both quotient and remainder. Tom Almy Tektronix, Inc. toma@tekgvs.TEK.COM
boykin@custom.UUCP (10/28/87)
> In article <146MAXHAM@RICE>, MAXHAM@RICE.BITNET (Mark Maxham) writes: > > But the 68000 MULS and MULU commands multiply two sixteen bit words > > into a 32 bit longword. Thus they are defined. Is the question > > how C translates from multiplicitive expressions into actual machine > > instructions? > > A general problem with HLL's is that they do not have the necessary > flexibility to handle situations like this. I do not know of any language > which has in its operation list an operation to multiply two 16 bit object > and get a 32 bit object. I don't believe this is a problem with the language, but with the compiler. The compiler should be able to optimize to use the instructions available to it. On most C compilers I've seen the following will use instructions like the 68000's MULS rather than a subroutine call: long x; /* 32-bit value */ short y, z; /* 16-bit value */ x = y * z; While this is implementation dependent, it has worked on most C compilers I've seen. Don't blame the language when the compiler (optimizer) is at fault. -- Joe Boykin ...necntc!custom!boykin
ark@alice.UUCP (10/30/87)
In article <776@custom.UUCP>, boykin@custom.UUCP writes: > I don't believe this is a problem with the language, but with > the compiler. The compiler should be able to optimize to use > the instructions available to it. On most C compilers I've > seen the following will use instructions like the 68000's MULS > rather than a subroutine call: > long x; /* 32-bit value */ > short y, z; /* 16-bit value */ > x = y * z; > While this is implementation dependent, it has worked on most > C compilers I've seen. Don't blame the language when the > compiler (optimizer) is at fault. On a machine with a 16-bit multiply that gives a 16-bit product, the compiler is completely justified in using that multiply and then sign-extending the result to 32 bits. If you have any thoughts about portability, you should be writing: x = (long)y * (long)z; And yes, I have seen compilers that will translate that to a single 16x16=32 multiply.
barmar@think.COM (Barry Margolin) (10/30/87)
In article <120@babbage.acc.virginia.edu> mac3n@babbage.acc.virginia.edu (Alex Colvin) writes: >In article <593@l.cc.purdue.edu>, cik@l.cc.purdue.edu (Herman Rubin) writes: >> A general problem with HLL's is that they do not have the necessary >> flexibility to handle situations like this. I do not know of any language >> which has in its operation list an operation to multiply two 16 bit object >> and get a 32 bit object. PL/I's default is to do just this! And if you multiply "fixed bin (12,5)" (12 bits with 5 after the binary point) by "fixed bin (16,3)" the default result is "fixed bin (28,8)". Imagine -- a language that follows the rules for arithmetic that we learned in grade school! For cases where you know that the result will not be the default (usually when one of the operands is a literal, and the automatically-generated data type isn't appropriate), there is a version of the multiplication operator that lets you specify the size of the result: result = multiply (var, 3, 16, 3); which means "multiply var by 3 giving a sixteen-bit result with three bits after the binary point)." --- Barry Margolin Thinking Machines Corp. barmar@think.com seismo!think!barmar
gwyn@brl-smoke.ARPA (Doug Gwyn ) (10/30/87)
In article <2262@sfsup.UUCP> mpl@sfsup.UUCP (M.P.Lindner) writes: >3. as for the people who say "Never use the basic types", I say the following: Mike gave good advice -- heed it. One additional note: ANSI C will guarantee minimum sizes for the basic integer data types. If you KNOW that all values will fit in a minimum implementation of the data type, you can use it when storage space is a significant factor. Otherwise, (int) is usually the type that is the fastest; however, it may be only 16 bits long so if that isn't enough for your application you have no choice but to use long (guaranteed to be at least 32 bits). If a long isn't enough, you'll have to find or develop a multiple-precision package and pay the speed penalty.