[comp.sys.mac.programmer] Float to integer conversion problem in LSC 3.0?

eacj@batcomputer.tn.cornell.edu (Julian Vrieslander) (08/08/88)

I hope someone can explain this one for me.  The following code fragment
is a simplified version of a routine that was giving me unexpected
results.  The results below were obtained in LightspeedC version 3.0,
running under System 6.0:

        double d;
        long m,n;
	
        m = 126.0;          /* m becomes 126 */	
        d = 12.6 * 10.0;    /* d becomes 126 */
        n = d;              /* n becomes 125 !! */
		
I cannot understand why n gets "rounded down" to 125.  Am I missing
something subtle about C syntax or IEEE type conversions, or is this a bug
in SANE or LSC?  The variable values shown in the comments were verified
with the LSC debugger and with my own debugging dialog.  If I use the
debugger to force a value of 126.0 into d before the last line is
executed, then n gets the correct result.  What's happening here?    
-- 
Julian Vrieslander     "Don't rush me... you'll get a rotten miracle."
Neurobiology & Behavior, W250 Mudd Hall, Cornell University, Ithaca NY 14853    
UUCP: {cmcl2,decvax,rochester,uw-beaver,ihnp4}!cornell!batcomputer!eacj
INTERNET: eacj@tcgould.tn.cornell.edu     BITNET: eacj@CRNLTHRY

drc@claris.UUCP (Dennis Cohen) (08/08/88)

In article <5813@batcomputer.tn.cornell.edu> eacj@tcgould.tn.cornell.edu (Julian Vrieslander) writes:
>        double d;
>        long m,n;
>	
>        m = 126.0;          /* m becomes 126 */	
>        d = 12.6 * 10.0;    /* d becomes 126 */
>        n = d;              /* n becomes 125 !! */
>		
>I cannot understand why n gets "rounded down" to 125.  Am I missing
>something subtle about C syntax or IEEE type conversions, or is this a bug
>in SANE or LSC?  The variable values shown in the comments were verified
>with the LSC debugger and with my own debugging dialog.  If I use the
>debugger to force a value of 126.0 into d before the last line is
>executed, then n gets the correct result.  What's happening here?    

Well, d is a double that is being assigned the product of two floats, the first
of which does not have an exact binary representation.  Because of this, d will
be 125.999(something).  When you now assign d to n (an integer type) it will
truncate (not round) to make the assignment.  This is not very nice, but it is
"correct" behavior (so far as C, Pascal, and most other languages are
concerned).

Dennis Cohen
Claris Corp.
------------
Disclaimer:  Any opinions expressed above are _MINE_!

anson@spray.CalComp.COM (Ed Anson) (08/08/88)

In article <5813@batcomputer.tn.cornell.edu> eacj@tcgould.tn.cornell.edu (Julian Vrieslander) writes:
>	
>        m = 126.0;          /* m becomes 126 */	
>        d = 12.6 * 10.0;    /* d becomes 126 */
>        n = d;              /* n becomes 125 !! */
>		
>I cannot understand why n gets "rounded down" to 125.

Because of the differences between binary and decimal notation, the value
12.6 cannot be represented exactly in floating point format.

My guess is that 12.6 gets converted to something just a hair lower than
12.6, which will always give the result described.

When converting from floating point to integer, I generally round the 
value, rather than simply truncate. That approach saves a lot of grief.
-- 
=====================================================================
   Ed Anson,    Calcomp Display Products Division,    Hudson NH 03051
   (603) 885-8712,      anson@elrond.CalComp.COM

set@teddy.UUCP (Sean E. Trowbridge) (08/08/88)

In article <5813@batcomputer.tn.cornell.edu> eacj@tcgould.tn.cornell.edu (Julian Vrieslander) writes:
>
>        double d;
>        long m,n;
>	
>        m = 126.0;          /* m becomes 126 */	
>        d = 12.6 * 10.0;    /* d becomes 126 */
>        n = d;              /* n becomes 125 !! */
>		
>I cannot understand why n gets "rounded down" to 125.
>Julian Vrieslander     "Don't rush me... you'll get a rotten miracle."

Floating point calculations are not always exact, since numbers are
converted from decimal to binary and back.  Since converting from a
float to an int simply truncates the fractional part, I would imagine
that 12.6 * 10.0 gives you 125.9999999, and assigning that value to an
int (long) gives you 125.

Sean Trowbridge

pollock@usfvax2.EDU (Wayne Pollock) (08/23/88)

In article <5813@batcomputer.tn.cornell.edu> (Julian Vrieslander) writes:
>
>        double d;
>        long m,n;
>	
>        m = 126.0;          /* m becomes 126 */	
>        d = 12.6 * 10.0;    /* d becomes 126 */
>        n = d;              /* n becomes 125 !! */
>		
>I cannot understand why n gets "rounded down" to 125.

This is just a result of floating point roundoff error.  To
make things work right when assigning a float or double to an int or
long, always add a small amount like this:

		n = d + 0.00001;

if you want to truncate accurately, or use:

		n = d + 0.5;

or some library routine if you want to round the number.  Assuming the
default conversions will always work perfectly is just asking for
trouble.

Wayne Pollock (The MAD Scientist)	pollock@usfvax2.usf.edu
Usenet:		...!{uflorida, codas}!usfvax2!pollock
GEnie:		W.POLLOCK

palmer@tybalt.caltech.edu (David Palmer) (08/23/88)

In article <1120@usfvax2.EDU> pollock@usfvax2.usf.edu.UUCP (Wayne Pollock) writes:
>  ....
>, or use:
>
>		n = d + 0.5;
>
>or some library routine if you want to round the number.  Assuming the
>default conversions will always work perfectly is just asking for
>trouble.

Use a library routine.  n=d + 0.5 does not properly round d if d < 0
(or more precisely, d < -0.5).  if d=-1.0, for instance, d+0.5 = -0.5
which is truncated to 0 when it is assigned to an integer variable.

As long as you have thoroughly memorized K&R's white book, you should have
no problem.

		David Palmer
		palmer@tybalt.caltech.edu
		...rutgers!cit-vax!tybalt.caltech.edu!palmer
			"Flowers -- Just say NO!!"
					- Mighty Mouse