Many thank to all, who responded to my initial question about double
precision rounding problem. To remind:
double var=20.5 ;
will store 20.4999990000000 in var
Encouraged by the responses I did some more research and look at the
results:
double var=20.5 is translated into something like:
move.l 0x40348000, &var
clr.l &var+4
which as I understand copies 4 "significant" bytes to first four bytes of
var and set the remaining four to zero. So the value actually stored was
0x40348000 00000000
However when I compiled
double var=20.49999999999999999 ;
I got
move.l 0x40348000, &var
move.l 0x00000001, &var+4
So the value actually stored was 0x40348000 0000001, which is larger than
the first one by the least significant byte.
Surprise, surprise, the value was actually displayed later on as 20.5!
To summarize, it looks like value 20.5 is wrongly translated during the
compiling to its double precision byte representation. In the first case
20.5 is recognized as a float number instead of double. Effectivelly, I got
a paradoxical result that 20.5<20.499999999999999, which is obviously
wrong.
1. Maybe I need to explicitly say that I want this value to be treated as
double (something like writing 400L to make a number long)? Anyone know the
right suffix?
2. I am pretty new to the PalmOS world, if it is indeed a bug, how should I
report it to get fast response?
Marcin Frelek
From: Ade Barkah <[EMAIL PROTECTED]> on 11.05.99 23:56
Please respond to [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
cc: (bcc: Marcin Frelek-M/PGI)
Subject: Re: Double precision number problem.
>Not all decimal values can be represented in this float format. As
>the integer part gets larger there are fewer bits remaining for the
>decimal part. Hence inaccuracies.
Yes, exactly! Instead of thinking about and "integer" part and a
"decimal" part, however, you should think in terms of the "significant
digits" part and the "exponent" part (to use the terms loosely.)
But "running out of bits" is only half of the problem.
Suppose a floating point which can handle four significant decimal
digits. Then we can easily represent the following numbers:
123.4 = 1.234 x 10^2
12.34 = 1.234 x 10^1
1.234 = 1.234 x 10^0
.1234 = 1.234 x 10^(-1)
12340000000 = 1.234 x 10^10
0.000001234 = 1.234 x 10^(-6)
As you can see, all the above numbers contain exactly the same amount
of significant digits (four.) What we're doing is simply using the
exponent to "shift" (or "float") the decimal point.
But, of course, we actually need to work in binary. So, let's go back
to the 20.5 example. Maybe, we'll store it this way:
20.5 = 2.05 x 10^1 (decimal)
Hmm, how do we represent '2.05' in binary ? The 2 part is easy, it
is simply binary '10'. How about the '.05' part ? Let's see the old
binary table for fractions:
2^-1 2^-2 2^-3 2^-4 2^-5 2^-6 (with exponents)
---------------------------------------------------------------------
1/2 1/4 1/8 1/16 1/32 1/64 (in fractions)
.5 .25 .125 .0625 .03125 .015625 (in decimal form)
Well, from the above, there is no binary fraction that is equivalent
to '0.05'. So, we need to approximate 2.05. Here are some attempts:
(binary) .1 = (decimal) 0.5 (way off)
(binary) .0001 = (decimal) 0.0625 (closer)
(binary) .00001 = (decimal) 0.03125 (too small)
(binary) .000011 = (decimal) 0.046875 (closest)
As hard as we try, we can't represent "0.05" decimal in binary form!
It turns out that there are many seemingly "simple" decimal fractions
which can't be exactly represented in binary, so that's why you're
seeing them approximated.
All of the above, unfortunately, doesn't answer why 20.5 is being
stored as 20.499999000 in double precision. It should be much more
accurate than that!
Regards,
-Ade