7

when I do 5.2 - 2.3 in ghci I'll get 2.9000000000000004 instead of 2.9. Also such ugly (and for a human WRONG) results shows up on other places when working with Double or Float.

Why does this happen? (this is just for curiosity, not my real question)

My real question: How do I tell ghci to not do that, and show the results of Operations on Doubles just as any other programming language (and calculator) would and just as every 15 year old would write them?

This is just so annoying when I use ghci as a nice calculator and work on lists on which I perform such operations.

map ((-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4]
[-1.7000000000000002,-1.5,-2.9000000000000004,-4.1000000000000005,0.9999999999999998,-6.000000000000001,-11.399999999999999,-6.7,-5.2,-0.10000000000000009]

This just doesn't help when using the numbers on a piece of paper afterwards

Thanks in advance :)

Dender
  • 165
  • 1
  • 7
  • 3
    just as a side comment, this is probably the most commonly asked question ever in the history of ever. – Justin L. Jul 22 '13 at 06:31

4 Answers4

18

Why does this happen?

Because certain floating point numbers cannot be represented by a finite number of bits without rounding . Floating-point numbers have a limited number of digits, they cannot represent all real numbers accurately: when there are more digits than the format allows, the leftover ones are omitted - the number is rounded.

You should probably read What Every Computer Scientist Should Know About Floating-Point Arithmetic and this answer.

Community
  • 1
  • 1
AllTooSir
  • 48,828
  • 16
  • 130
  • 164
8

How do I tell ghci to not do that, and show the results of Operations on Doubles just as any other programming language (and calculator) would and just as every 15 year old would write them?

Since those results are the actual results GHCI (and your standard calculator*) calculates you cannot change the internal representation of the result (see TNI's answer). Since you want to show only a fixed number of decimals it's more a matter of the presentation (compare to printf("%f.2",...) in C).

A solution to this can be found in https://stackoverflow.com/a/2327801/1139697. It can be applied like this:

import Numeric
fixedN :: (RealFloat b) => Int -> b -> String
fixedN a b = showFFloat (Just a) b ""

map (fixedN 2 . (-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4]
-- result: ["-1.70","-1.50","-2.90","-4.10","1.00","-6.00",...]

Note that this won't be feasible if you want to continue calculation. If you want exact arithmetic, you're better of by using Rationals anyway. Don't forget that your input should be rational aswell in this case.

* yes, even your standard calculator does the same thing, the only reason you don't see it is the fixed presentation, it cannot show more than a fixed number of decimals.

Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • 1
    Actually, many of the simpler pocket calculators use [BCD](http://en.wikipedia.org/wiki/Binary-coded_decimal), which doesn't suffer from this problem but is completely unsuitable for doing anything more advanced than square roots efficiently. You could say it circumvents the bug in humans' way of counting... – leftaroundabout Jul 21 '13 at 10:11
3

It's the nature of floating point numbers that they cannot exactly represent real (nor rational) numbers. Haskell default conversion to string ensures that when the number is read back in you get exactly the same representation. If you want a different way to print numbers you can make your own type which shows numbers differently.

Something like (untested):

newtype MyDouble = MyDouble {getMyDouble :: Double}
            deriving (Eq, Ord, Num, Real, RealFrac, Fractional, Floating)
instance Show MyDouble where show = printf "%g" . getMyDouble
default (MyDouble)

This creates a copy of the Double type, but with a different Show instance that just prints a few decimals. The default declaration makes the compiler pick this type when there is an ambiguity. Oh, and to make this work you need a few language extensions.

You could also try the CReal type from the numbers package.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
augustss
  • 22,884
  • 5
  • 56
  • 93
3

How do I tell ghci to not do that, and show the results of Operations on Doubles just as any other programming language (and calculator) would

Did you actually try "any other programming language"? Or are you just bullying around?

FWIW, here is the output of an interpreter for a language that uses the JVM:

frege> 5.2 - 2.3
2.9000000000000004

Looks to me as if you would get that same result with all JVM languages. And since the JVM is written in C++, chances are that there the result is the same. And since most languages runtimes are written in C/C++, chances are you get that very same result also with those languages. Unless they are so "user friendly" and perform rounding you didn't ask for.

Ingo
  • 36,037
  • 5
  • 53
  • 100