Newsgroups: comp.lang.pascal
Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!sdd.hp.com!elroy.jpl.nasa.gov!ucla-cs!ucivax!milne
From: milne@ics.uci.edu (Alastair Milne)
Subject: Re: Is this a bug in TurboPascal
Message-ID: <281F9DD7.15836@ics.uci.edu>
Organization: UC Irvine Department of ICS
References: <1991May1.021059.2129@ux1.cso.uiuc.edu> <1991May1.060345.26511@newsserver.sfu.ca>
Distribution: na
Date: Thu, 2 May 1991 05:04:23 GMT
Lines: 80

In <1991May1.060345.26511@newsserver.sfu.ca> shephard@newsserver.sfu.ca (Gordon Shephard) writes:

>>var
>>    xx,yy,c1,c2,c3,c4: integer;

>>begin
>>    xx := 639; yy := 479; 
>>    c1 := Trunc(50*xx/639); c2 := Trunc(50*yy/479);
>>    c3 := Trunc(300*xx/639); c4 := Trunc(250*yy/479);
>>    writeln(xx,yy,c1,c2,c3,c4);
>>end.

>>OUTPUT:
>>639,479,50,50,-7,-23

>>How does it happen that the last two numbers are wrong and the rest right???

    If you have never before seen integer overflow, you are very lucky.

    Look at the order of operations you are probably getting in the 
    3rd line of assignments, and consider what the intermediate
    results probably are: 300*639, 250*479.  Far bigger than MaxInt.

    Yes, I know -- you looked at those assignments and thought 
    "anybody in his right mind will see a fraction here with numerator
    and denominator the same, so they'll do that first."  But Pascal
    won't.

    If you want a specific order of evaluation for an expression, make *sure*
    you parenthesise the parts to be done first.

    Try TRUNC(300 * (xxx/639)).  I think you'll find a difference.

>TP also operates in the Lowest Common Denominator when Doing Arithmetic.
>E.G. All of your variables are integers, so TP worked with integers.

     No.  The '/' operator is floating-point division, no matter the 
     type of its operands.  For integer division, DIV must be used 
     (MOD is integer division too, but a different operation).

     Also, having yielded a floating-point result from the division,
     Pascal then assumes floating-point multiplication (that is, assuming
     the division is done first, as the poster intended.)  That is, 
     if either operand of "*" is floating-point, so is the result.

     This is why the TRUNC operation was needed before the assignment, 
     to obtain the integer part of a floating point result.

>(Note, if you'd have multiplied by 300.0 and 250.0, always a good habit
>when you risk overflow, The answers would have been correct.)

      This must be my day for disagreeing.  Floating-point often involves
      representational inaccuracy -- and is often slower to boot, though
      with some newer CPU's that isn't always true.  

      Within a certain range outside integer's scope, floating-point 
      is safe enough -- but it's no panacea.  There are points, I grant,
      where you wind up needing it for its range allowance, but you pay
      a price.  Certainly it's not the primary answer in the case 
      we have here.

>When you multiplied 300*639, your answer is 191700.  So not only do you
>wrap around to the negative values (32767+1=-32768 in integer
>arithmetic.  Just like a speedometer), you also lose some data
>(overflow).  ... 

       Here I agree completely.  Overflow is indeed losing data.

> The easiest way around all of this is to add .0 to at least one number
> in an equation which could cause trouble.  ...

       The best way around all this is to make sure the evaluation
       order that was intended is in fact used, with judicious use
       of parentheses.  And of course, be *aware* of the intermediate
       operations and results in an evaluation.

       As we see here, they make a difference.


       Alastair Milne
