murphy@pur-phy (William J. Murphy) (03/06/90)
Yesterday, I was debugging a program of mine and came across an interesting difference between GNU C and Turbo C. Here is the buggy code: long SUM; short data1, data2, data3, data4, data5; SUM = data1 + data2 + data3 + data4 + data5; Here is the problem, when the sum of data? < 32767 it sums correctly on both GNU C and TC. Hwen the sum of data? > 32767, TC does the rollover and becomes negative while GNU C carries the sum as a long and returns the correct answer. Which one is correct? (according to ANSI standards) Of course the fix is simple, but the rest of the program had problems that are not so simple to fix under MSDOS. SUM = (long)data1 + (long)data2 + (long)data3 + (long)data4 + (long)data5; solved the problem. -- Bill Murphy murphy@newton.physics.purdue.edu Enjoying my Amiga 2000, but holding out for a real computer: The Amiga 3000!!
sar@datcon.UUCP (Simon A Reap) (03/09/90)
In article <3210@pur-phy> murphy@newton.physics.purdue.edu.UUCP (William J. Murphy) writes: >long SUM; >short data1, data2, data3, data4, data5; >SUM = data1 + data2 + data3 + data4 + data5; >Here is the problem, when the sum of data? < 32767 it sums correctly on both >GNU C and TC. Hwen the sum of data? > 32767, TC does the rollover and >becomes negative while GNU C carries the sum as a long and returns the : >SUM = (long)data1 + (long)data2 + (long)data3 + (long)data4 + (long)data5; >solved the problem. Microsoft C 5.1 (under OS/2) does the same (wrong) thing. BTW, you only need to (long) cast one of the data? to get the right result. -- Enjoy, yerluvinunclesimon Opinions are mine - my cat (1CC) has her own ideas Reach me at sar@datcon.co.uk, or ...!mcvax!ukc!pyrltd!datcon!sar
scjones@sdrc.UUCP (Larry Jones) (03/09/90)
In article <3210@pur-phy>, murphy@pur-phy (William J. Murphy) writes: > [ should long = short + short; be done with short or long > arithmetic? ] Either is acceptable. ANSI C requires the arithmetic to be done in short -- if the result overflows, the results are undefined, thus getting the right answer (by actually doing long arithmetic) is acceptable. ---- Larry Jones UUCP: uunet!sdrc!scjones SDRC scjones@SDRC.UU.NET 2000 Eastman Dr. BIX: ltl Milford, OH 45150-2789 AT&T: (513) 576-2070 "You know how Einstein got bad grades as a kid? Well MINE are even WORSE!" -Calvin
flee@shire.cs.psu.edu (Felix Lee) (03/09/90)
Re the claim that
short a, b;
long tot = a + b;
gets the wrong answer if (a + b > 32767),
>Microsoft C 5.1 (under OS/2) does the same (wrong) thing.
It's not the wrong thing. The shorts are promoted to ints, not longs,
before the addition is performed. This can overflow if your int is
shorter than your long, as with many PC compilers.
If you want to be portable and get the correct answer, you should cast
(at least one of) the operands to long before adding:
long tot = (long) a + b;
--
Felix Lee flee@shire.cs.psu.edu *!psuvax1!flee
CMH117@psuvm.psu.edu (Charles Hannum) (03/09/90)
In article <1180@sdrc.UUCP>, scjones@sdrc.UUCP (Larry Jones) says: > >In article <3210@pur-phy>, murphy@pur-phy (William J. Murphy) writes: >> [ should long = short + short; be done with short or long >> arithmetic? ] > >Either is acceptable. ANSI C requires the arithmetic to be done >in short -- if the result overflows, the results are undefined, >thus getting the right answer (by actually doing long arithmetic) >is acceptable. But relying on the result to be correct in *unacceptable*. Virtually, - Charles Martin Hannum II "Klein bottle for sale ... inquire within." (That's Charles to you!) "To life immortal!" cmh117@psuvm.{bitnet,psu.edu} "No noozzzz izzz netzzzsnoozzzzz..." c9h@psuecl.{bitnet,psu.edu} "Mem'ry, all alone in the moonlight ..."
tim@nucleus.amd.com (Tim Olson) (03/10/90)
In article <E24hr$1@cs.psu.edu> flee@shire.cs.psu.edu (Felix Lee) writes: | Re the claim that | short a, b; | long tot = a + b; | gets the wrong answer if (a + b > 32767), | >Microsoft C 5.1 (under OS/2) does the same (wrong) thing. | | It's not the wrong thing. The shorts are promoted to ints, not longs, | before the addition is performed. This can overflow if your int is | shorter than your long, as with many PC compilers. | | If you want to be portable and get the correct answer, you should cast | (at least one of) the operands to long before adding: | long tot = (long) a + b; This is correct, but note that in the original poster's case, there was a large sequence of sums: tot = a + b + c + d + e + f; where tot is a long and the others are shorts. In this case, it is not sufficient to cast just one of the operands to a long, because the order of evaluation of the sums is undefined. The standard widening rules apply only to the two operands of an operation, so if we cast only "a" to be a long, and the compiler chose to evaluate the sums from right-to-left, then only the last sum would be done with long operands. -- Tim Olson Advanced Micro Devices (tim@amd.com)
coy@ssc-vax.UUCP (Stephen B Coy) (03/10/90)
In article <60@datcon.UUCP>, sar@datcon.UUCP (Simon A Reap) writes: > In article <3210@pur-phy> murphy@newton.physics.purdue.edu.UUCP > (William J. Murphy) writes: > >long SUM; > >short data1, data2, data3, data4, data5; > >SUM = data1 + data2 + data3 + data4 + data5; > >Here is the problem, when the sum of data? < 32767 it sums correctly on both > >GNU C and TC. Hwen the sum of data? > 32767, TC does the rollover and > >becomes negative while GNU C carries the sum as a long and returns the > : > >SUM = (long)data1 + (long)data2 + (long)data3 + (long)data4 + (long)data5; > >solved the problem. > Microsoft C 5.1 (under OS/2) does the same (wrong) thing. BTW, you only need > to (long) cast one of the data? to get the right result. The Real(tm) cause of this problem lies in the fact that the MS-DOS compilers default to a 16 bit int while GCC defaults to a 32 bit int. As stated in K&R Classic, p.41, during arithmetic operations "char and short are converted to int". MSC and TC do their expression evaluation in 16 bit integers and then convert the result to long (32-bit) for the assignment. GCC does its evaluation in 32 bit integers and then does the assignment. Both are legal and consistant interpretations of the standard. Caveat programmer. > yerluvinunclesimon Opinions are mine - my cat (1CC) has her own ideas > Reach me at sar@datcon.co.uk, or ...!mcvax!ukc!pyrltd!datcon!sar Stephen Coy uw-beaver!ssc-vax!coy
bright@Data-IO.COM (Walter Bright) (03/13/90)
In article <29446@amdcad.AMD.COM> tim@amd.com (Tim Olson) writes:
< tot = a + b + c + d + e + f;
<where tot is a long and the others are shorts. In this case, it is
<not sufficient to cast just one of the operands to a long, because the
<order of evaluation of the sums is undefined. The standard widening
<rules apply only to the two operands of an operation, so if we cast
<only "a" to be a long, and the compiler chose to evaluate the sums
<from right-to-left, then only the last sum would be done with long
<operands.
Not true. The order of evaluation is undefined, but the *binding* is
defined. The binding is defined to be:
tot = (((((a + b) + c) + d) + e) + f);
Thus if the expression is written as:
tot = (long)a + b + c + d + e + f;
it is defined to be equivalent to:
tot = ((((((long)a + b) + c) + d) + e) + f);
now we apply the standard integral promotions to get:
tot = ((((((long)a + (long)b) + (long)c) + (long)d) +
(long)e) + (long)f);
*NOW* the order in which the longs are added can be rearranged, but not
before!
Note also that:
tot = a + b + c + d + e + (long)f;
is equivalent to:
tot = (long)(a + b + c + d + e) + (long)f;
so beware.
tim@nucleus.amd.com (Tim Olson) (03/13/90)
In article <2374@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes: | In article <29446@amdcad.AMD.COM> tim@amd.com (Tim Olson) writes: [ some incorrect drivel about order of evaluation and casting] | Not true. The order of evaluation is undefined, but the *binding* is | defined. Walter is right. I had just been looking at some code that relied upon order-of-evaluation, and had that on the brain... ;-) -- Tim Olson Advanced Micro Devices (tim@amd.com)