[comp.lang.pascal] Is this a bug in TurboPascal?

phys169@csc.canterbury.ac.nz (05/01/91)

In article <1991May1.021059.2129@ux1.cso.uiuc.edu>, husak@ux1.cso.uiuc.edu (BugsBunny) writes:
> I'm running the following in TP and get the wrong answer.. Please correct
> me if I'm wrong...
> 
> program Is_this_wrong; 
> 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.
> 
This is a common problem: you are multiplying two integers to get a temporary
integer result. For example, when calculating 300*xx/639 it works out 300*xx
to 16 bits accuracy (same accuracy as the 300 and xx), which is not the 191700
you would expect. Either you should change the declaration of xx & yy to be
longint (or reals, if you like), or change the code to..
  c1 := Trunc(50.0*xx/639.0); c2 := Trunc(50.0*yy/479.0);
  c3 := Trunc(300.0*yy/639);  c4 := Trunc(250.0*yy/479.0);

The reason this works is that 300.0*yy is a real result, which goes on to the
division by 639 (or 639.0, either will do, but 639.0 is preferrable).

Note that 300*479/639 gives the expected result with TP 5, since 300*479 is
evaluated at compile time to give a longint result, so it knows to use 32 bits
of accuracy. Another interesting point is that 120*b (where b is a byte
variable set to 100) gives the correct answer, when you might have thought it
would be clipped to 8 bits. Presumably 100 is an integer constant, not a byte
constant.

BTW, it is a good idea to make sure range checking is on; it catches some
cases like this (but not this particular one, I'm afraid). 

Hope this helps,
Mark Aitchison, Physics, University of Canterbury, New Zealand.

ravn@imada.ou.dk (Thorbjoern Ravn Andersen) (05/06/91)

phys169@csc.canterbury.ac.nz writes:

[Stuff deleted]
>longint (or reals, if you like), or change the code to..
>  c1 := Trunc(50.0*xx/639.0); c2 := Trunc(50.0*yy/479.0);
>  c3 := Trunc(300.0*yy/639);  c4 := Trunc(250.0*yy/479.0);

>The reason this works is that 300.0*yy is a real result, which goes on to the
>division by 639 (or 639.0, either will do, but 639.0 is preferrable).

You may also force the computation into real mode, by doing the
division first.  Calculating it like
   
   c3:= Trunc(300/639 * yy)

will have the same result.  I do like this because I do not think the
.0's are pretty.  I do not know, however, how this may affect your
portabillity with other compilers.  [BTW. This was checked with Turbo
5.0, I do not know if it has been changed in later versions]
  

>BTW, it is a good idea to make sure range checking is on; it catches some
>cases like this (but not this particular one, I'm afraid). 

As far as I know, there is *NO* checking on overflow on integer
calculations.  The range check is only active in subranges and index
variables.

-- 
Thorbj\o{}rn Ravn Andersen 'Normally I kill people for money.  You are my
ravn@imada.ou.dk            friend; I will kill you for nothing' -- Chico Marx

Justice, n.: