4

I found out the floating point multiplication in mit-scheme is not accurate, for example,

1 ]=> (* 1991.0 0.1)

will produce

;Value: 199.10000000000002

Could you please help explain the appearance of the weird trailing number “2”?

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
TJH
  • 73
  • 1
  • 5
  • 2
    http://floating-point-gui.de/ – This company is turning evil. Jan 14 '18 at 16:58
  • 1
    I'm voting to close this question as off-topic because this is not a problem specific to Unix or Linux. Instead it is a mathematics problem relating to the infinite representation of the number one-tenth in base two, which will affect equally any system that uses fixed- or floating-point numbers instead of rationals. – Fox Jan 14 '18 at 18:03

2 Answers2

10

Remember that computers are binary,

No matter how many base 2 digits you’re willing to use, the decimal value 0.1 cannot be represented exactly as a base 2 fraction.

In base2 1/10 is 0.0001100110011001100110011... (repeating forever)

Unfortunately this is result of binary floating point, and any language that uses the FPU will have similar results, like Python.

In [1]: 1991.0 * 0.1
Out[1]: 199.10000000000002

In [2]: 0.1 + 0.2
Out[6]: 0.30000000000000004

This is a Representation error because often decimal fractions cannot be represented exactly as binary (base 2) fractions.

Perl, C, C++, Java, Fortran, Python and scheme will all demonstrate this behavior.

gdahlm
  • 1,231
  • 10
  • 7
  • 1
    Thanks a lot for your explanation! I understand. Initially, I tried to evaluate the expression in both scheme and clisp, and clisp just printed out 199.1, which made me think that there might be something wrong with scheme. Now, I know that clisp must have returned the round-off of the value, while in memory both clisp and scheme should have the same representation. – TJH Jan 14 '18 at 04:55
  • 1
    @TJH: many languages or implementations round off floating point values when _displayed_ -- or more exactly when converted to textual form, as is normally done for display and sometimes for other purposes. – dave_thompson_085 Jan 14 '18 at 08:07
  • `perl6 -e 'say 1991.0 * 0.1'` gives 199.1 and `perl6 -e 'say( 0.3 - 0.2 - 0.1 == 0 )'` gives True. This is unlike Perl5, C, C++, Java, etc – thrig Jan 14 '18 at 15:52
7

This quote is from memory and so probably not quite right but it conveys the essence of the problem: "Operating on floating point numbers is like moving piles of sand: every time you do it, you lose a little sand and you get a bit of dirt" (from Kernighan and Plauger's "Elements of programming style" IIRC). Every programming language has that problem.

NickD
  • 2,866
  • 1
  • 10
  • 21
  • 4
    Yes, well, that's what it _feels_ like if you look too closely (as here). But it's important to remember that the operations in itself aren't fuzzy, it's just that some values can't be represented exactly, so you get the nearest one that can be. For results that _can_ be represented exactly, you get exactly the result you should. – ilkkachu Jan 14 '18 at 08:04
  • 1
    @ilkkachu: indeed. The other answer is probably better in that it goes into the relevant detail. But it is a memorable quote! – NickD Jan 14 '18 at 14:30