admin管理员组

文章数量:1245697

It's a known fact that numbers like Double which correspond to IEEE 754 floating-point cannot represent numbers like 0.1 accurately.

But when I played around with it in REPL, I'm confused by the behaviour:

ghci> let x = 0.1 :: Double
ghci> :t x
x :: Double
ghci> import Text.Printf
ghci> printf "%.20f\n" x
0.10000000000000000000

To cross check myself, I used Python repl to do the same where I'm getting expected results:

>>> x = 0.1
>>> type(x)
<class 'float'>
>>> print(f"{x:.20f}")
0.10000000000000000555

Why am I seeing different and a unexpected result in the GHC repl ?

It's a known fact that numbers like Double which correspond to IEEE 754 floating-point cannot represent numbers like 0.1 accurately.

But when I played around with it in REPL, I'm confused by the behaviour:

ghci> let x = 0.1 :: Double
ghci> :t x
x :: Double
ghci> import Text.Printf
ghci> printf "%.20f\n" x
0.10000000000000000000

To cross check myself, I used Python repl to do the same where I'm getting expected results:

>>> x = 0.1
>>> type(x)
<class 'float'>
>>> print(f"{x:.20f}")
0.10000000000000000555

Why am I seeing different and a unexpected result in the GHC repl ?

Share Improve this question asked Feb 15 at 10:58 SibiSibi 48.7k18 gold badges104 silver badges171 bronze badges 2
  • 2 The culprit could be formatRealFloatAlt, which I believe tries to prefer trailing zeros when possible (?). I am not very sure about this, though -- its code is fairly complex, so mine is only a wild guess. Printing (1.0 / 49.0) * 49.0 seems to confirm this: trailing zeros are preferred over nines in 0.99999.... – chi Commented Feb 15 at 11:25
  • 1 Why is it unexpected? See also dl.acm./doi/10.1145/93542.93559 – Yuras Commented Feb 15 at 15:43
Add a comment  | 

1 Answer 1

Reset to default 5

The libraries that come with GHC are all based around the idea that when converting to decimal, you want the shortest representation that rounds to your float. If you want to see the most accurate representation instead, I believe you have to pull some tricks. Here's one example of a trick you can pull, using the numbers package:

Data.Number.CReal> showCReal 100 (realToFrac 0.1)
"0.1000000000000000055511151231257827021181583404541015625"

This is <100 digits despite requesting 100 digits because showCReal drops trailing zeros. Be careful not to drop the realToFrac -- it is secretly there to suggest to GHC that it choose Double for the type of the 0.1, using defaulting and possibly ghci's extended defaulting. Contrast:

Data.Number.CReal> showCReal 100 0.1
"0.1"

本文标签: Haskell39s double behaviourStack Overflow