[Pharo-project] Unexpected behavior of roundTo:
Andres Valloud
avalloud at smalltalk.comcastbiz.net
Sat Apr 9 20:19:32 CEST 2011
On 4/9/11 0:28 , Marcus Denker wrote:
>
> On Apr 9, 2011, at 9:09 AM, Andres Valloud wrote:
>
>> I think the real solution to these "problems" is to implement
>> decimal floating point as per IEEE-754/2008. \\
>
> The MPFR lib seems to me (as far as I understand) is inspired by IEEE
> 754
>
> <quote from the docs>
The docs seem to suggest MPRF implements variable precision binary
floating point numbers. IEEE-754/2008, as opposed to IEEE-754/1985,
also specifies types for base 10 (i.e.: decimal) floating point numbers.
In other words, 2.5 wouldn't be represented as (101)_2, but (25)_10.
Thus, going back to the original problem that caused this discussion,
> 2.8011416510246336 roundTo: 0.01
>
> returns
>
> 2.8000000000000003
the problem here is that there is no binary floating point number that
can represent the number 0.01. The arguments why this is so are the
usual (and I just put them here for the sake of completeness): binary
floating point numbers represent fractions of the form
+/- m * 2^k
where m, k are integers such that 0 <= m < M, and e <= k <= K. So let's
try to find which values of m and k match for 0.01:
1/100 = m * 2^k
Well, m is not zero, so it must be at least 1, and so k must be
negative. Set k' = -k and rearrange:
2^k' = 100m
Now we invoke the help of the fundamental theorem of arithmetic that
says integers can be factored into primes in only one way. On the left
we only have 2 as a prime factor. On the right, there is a factor of 5.
Therefore, we conclude the above equality is impossible. So, m and k
do not exist, and so no binary floating point number is equal to 0.01.
To make the story short, you cannot assume lossless operation just
because you can see a base 10 print string. If loss of precision is the
issue because we only have 2^k' on the left, let's try base 10 instead.
In other words, floating point numbers in which the base is 10
represent values of the form
+/- m * 10^k
where m, k are integers such that 0 <= m < M, and e <= k <= K. So let's
try to find which values of m and k match for 0.01:
1/100 = m * 10^k
So now we just match the fraction on the left with m=1 and k=-2. Done.
Of course, there are values that cannot be represented without loss of
precision, but the loss of precision involves only m and k. For example,
67423523487542376543765376234576235726345623472 = m * 10^k
when 0 <= m < M and M = 9. There are not enough digits in the mantissa,
so the result is going to be 7*10^k for some k. But this issue happens
as well with binary floating point numbers when k is positive. Try
67423523487542376543765376234576235726345623472 asFloat truncated
Increasing the precision of binary floating point numbers to arbitrary
precision help you if you need a bigger mantissa, but a bigger mantissa
does not solve the fundamental problem of binary floating point numbers
that causes imprecision whenever you use base 10 to write down values.
> MPFR is LGPL, so linking that in the VM or using it via FFI is no
> problem license wise.
I am not convinced that's what you need:
http://en.wikipedia.org/wiki/Decimal_floating_point
And it looks like Intel wrote a decimal floating point library, too...
now I need to check the license on this one as well:
http://software.intel.com/en-us/blogs/2008/03/06/intel-decimal-floating-point-math-library/
Andres.
More information about the Pharo-project
mailing list