
Am Sonntag 23 August 2009 15:27:48 schrieb Steve:
On Sun, 2009-08-23 at 15:12 +0400, Eugene Kirpichov wrote:
There is *not* the same problem in Python: $ python Python 2.6.2 (r262:71600, Jul 9 2009, 23:16:53) [GCC 4.4.0 20090506 (Red Hat 4.4.0-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
import math math.log10(1000)
3.0
import math math.log(1000,10)
2.9999999999999996
That is surprising. I think its a Python bug - the results should be consistent.
On the other hand, it is also desirable to have log(a,b) == log(a)/log(b). If you have a special implementation of log10, you must decide which consistency you want to break, log(a,10) == log10(a) or log(a,10) == log(a)/log(10).
Recent work in Python 3 (and Python 2.6) has improved the handling of floating point numbers, and addresses exactly the problem that Roberto has raised.
I see no reason why Haskell could not improve its handling of floating point numbers by using similar techniques.
You mean introducing a "log10" function into the definition of the Floating class ? That might be a proposal for Haskell Prime.
I was not thinking of the log10 function. I was thinking of the changes mentioned in http://docs.python.org/3.1/whatsnew/3.1.html where it says "Python now uses David Gay’s algorithm for finding the shortest floating point representation that doesn’t change its value. This should help mitigate some of the confusion surrounding binary floating point numbers."
Note however that that only concerns the output, not the underlying value. It doesn't change the fact that log(1000)/log(10) (== log(1000,10)) < 3 in Python, too.
Also, I had a problem using floating point in Python where
round(697.04157958254996, 10)
gave 697.04157958259998 which is closer to 697.0415795826 than the desired result of 697.0415795825
Well, 10^10*(697.04157958254996 :: Double) == 6970415795825.5, that gets rounded to 6970415795826 under both, round-half-up and round-half-to-even, and (6970415795826/10^10 :: Double) == 697.04157958259998 Though ghci displays it as 697.0415795826, unlike Python.
Its been fixed in the latest versions of Python:
round(697.04157958254996, 10)
697.0415795825
I'm not sure what the equivalent in Haskell is. Is there a function for rounding to a number of decimal digits ? I came up with this:
roundN :: Double -> Int -> Double roundN n ndigits = fromIntegral (round $ n * m) / m where m = 10 ^ ndigits
ghci> roundN 697.04157958254996 10 697.0415795826
which is not the desired result.
Prelude Numeric> let roundN :: Double -> Int -> Double; roundN x d = let { m = 10^(d+1); i = floor (m*x); r = i `mod` 10; j = if r < 5 then i-r else i-r+10 } in fromInteger j/m roundN :: Double -> Int -> Double roundN x d = fromInteger j / m where m = 10^(d+1) i = floor (m*x) r = i `mod` 10 j | r < 5 = i-r | otherwise = i+10-r ghci> roundN 697.04157958254996 10 697.0415795825 I haven't treated negative input, but, more importantly, floating point representation being what it is, there are cases where this doesn't do what you want/expect either.
Steve