incorrect simple floating point math

Discussion of Common Lisp
speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

incorrect simple floating point math

Post by speech impediment » Thu Jun 18, 2009 11:43 am

I am using Lisp-in-a-box (Clisp) and it is a hit and miss kind of thing with doing simple math. Sometimes I would get the correct answer and other times I get odd results. Here are a few examples of what I actually typed:

Correct:
(+ 2 2.4 5.1)
9.5

Wrong:
(+ 2 4.2 8.4)
14.599999

Any idea what is going on?

Tom
Posts: 22
Joined: Sat Jun 28, 2008 12:52 pm
Location: Wichita, KS
Contact:

Re: incorrect simple floating point math

Post by Tom » Thu Jun 18, 2009 1:05 pm

There is nothing incorrect in the examples you posted. Please review the following links.

Wikipedia
http://en.wikipedia.org/wiki/Floating_point

"What Every Computer Scientist Should Know About Floating-Point Arithmetic"
http://docs.sun.com/source/806-3568/ncg_goldberg.html

~ Tom

smithzv
Posts: 94
Joined: Wed Jul 23, 2008 11:36 am

Re: incorrect simple floating point math

Post by smithzv » Thu Jun 18, 2009 2:32 pm

speech impediment wrote:I get odd results
If these kinds of floating point errors are actually a problem, you have the option of avoiding floating point all together. You could use rational number arithmetic.

Code: Select all

(+ 2 12/5 51/10)
(+ 2 46/5 42/5)
...which could be facilitated by using the RATIONALIZE function in CL.

Code: Select all

(apply #'+ (mapcar #'rationalize '(2 2.4 5.1)))

speech impediment
Posts: 36
Joined: Mon May 04, 2009 5:19 pm

Re: incorrect simple floating point math

Post by speech impediment » Thu Jun 18, 2009 3:36 pm

If these kinds of floating point errors are actually a problem, you have the option of avoiding floating point all together. You could use rational number arithmetic.
Wow... is this how most programmers program mathematically when using numbers with decimal points? If not, how does one generally program with mathematical accuracy? I've been reading links for a while and it seems like there isn't an easy solution to doing accurate math. Maybe Vedic Mathematics? ;-)

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: incorrect simple floating point math

Post by nuntius » Thu Jun 18, 2009 6:25 pm

Financial calculations are performed using decimal (base10) as opposed to binary (base 2) arithmetic. In decimal arithmetic, your examples would give the same results you learned in school. In binary arithmetic, there are no exact representations for 1/5, 1/25, 1/125, etc.; thus you see "errors" in the calculation.

Most decimal calculations are done using "binary coded decimal", where each 4 binary bits (0-15) is used to store one decimal digit (0-9).

Surprisingly, a bit of searching around didn't turn up any decimal arithmetic libraries for CL. If someone wanted to write one, I would recommend that they start by reading the docs on the following page.
http://speleotrove.com/decimal/

findinglisp
Posts: 447
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX
Contact:

Re: incorrect simple floating point math

Post by findinglisp » Thu Jun 18, 2009 7:30 pm

speech impediment wrote:
If these kinds of floating point errors are actually a problem, you have the option of avoiding floating point all together. You could use rational number arithmetic.
Wow... is this how most programmers program mathematically when using numbers with decimal points? If not, how does one generally program with mathematical accuracy? I've been reading links for a while and it seems like there isn't an easy solution to doing accurate math. Maybe Vedic Mathematics? ;-)
Most programmers just get it wrong.

The ones who really care about numerical results have scars to prove it.
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: incorrect simple floating point math

Post by gugamilare » Thu Jun 18, 2009 8:16 pm

speech impediment wrote:
Wow... is this how most programmers program mathematically when using numbers with decimal points? If not, how does one generally program with mathematical accuracy? I've been reading links for a while and it seems like there isn't an easy solution to doing accurate math. Maybe Vedic Mathematics? ;-)
If you want "mathematical accuracy" then you need rational numbers. Any floating point arithmetic will need to round numbers (and this will inevitably make the sum operation not associative). The decimal base is no less of an issue than binary base (there is no way represent 1/3 or 2/3 in a finite decimal number, but in base 3 this is an easy task). The difference in this problem is that you are providing simple decimal numbers and converting them to binary representation.

I also faced this problem once, when I made a simple money change calculator - you provide an amount of money and it returns how many and which coins you should use to pay. For instance:

(exchange 0.64) =>
1 coin of 50 cents
1 coin of 10 cents
4 coins of 1 cent

The solution I came up with was to multiply the number by 100 and round it before calculating the amount of coins.

simon
Posts: 16
Joined: Wed May 13, 2009 9:12 am

Re: incorrect simple floating point math

Post by simon » Thu Jun 18, 2009 9:43 pm

Wow... is this how most programmers program mathematically when using numbers with decimal points? If not, how does one generally program with mathematical accuracy? I've been reading links for a while and it seems like there isn't an easy solution to doing accurate math. Maybe Vedic Mathematics? ;-)
Floating point numbers are extremely useful, but in order to get sensible results you need to know what they are and what you are doing.

People have noted things like BCD and other techniques, but the thing you have to realize is that there is no single "right" answer to the fundamental problem that you can't represent an arbitrary real number to full precision in a computer.

BCD works well because the fractional part is of known magnitude.

Basically, floating point numbers are rational approximations to real numbers that a) have a fixed precision and b) are logarithmically distributed over a large range of magnitudes. This is extremely useful but as you've already found out, if you just treat them as real numbers you'll run into grief easily.

Harleqin
Posts: 71
Joined: Wed Dec 17, 2008 5:18 am
Location: Bonn, Germany

Re: incorrect simple floating point math

Post by Harleqin » Fri Jun 19, 2009 8:05 am

Since someone mentioned financial calculations: Never do financial calculations with floats!

Floats are just a representation for non-integer, non-rational measurements. Their accuracy is, of course, limited by the number of places after the point. A base 2 float with x places after the point naturally has less precision than a base 10 float with x places. If you are converting a base 2 float with 10 places to base 10, then anything after the first 3 places of the result cannot be actual information coming from the base 2 float.

If you have precise fractions, don't use floats. The simplest way in Common Lisp is to use rationals, and convert input with RATIONALIZE and output for display with FLOAT. For fixed-point arithmetic (like financials), just using integers as multiples of the lowest unit (e.g. cents) is also a good way.
"Just throw more hardware at it" is the root of all evil.
Svante

findinglisp
Posts: 447
Joined: Sat Jun 28, 2008 7:49 am
Location: Austin, TX
Contact:

Re: incorrect simple floating point math

Post by findinglisp » Fri Jun 19, 2009 9:13 am

nuntius wrote:Most decimal calculations are done using "binary coded decimal", where each 4 binary bits (0-15) is used to store one decimal digit (0-9).

Surprisingly, a bit of searching around didn't turn up any decimal arithmetic libraries for CL. If someone wanted to write one, I would recommend that they start by reading the docs on the following page.
http://speleotrove.com/decimal/
Interestingly, old HP calculators used to use a form of "floating point BCD" (my term, not HP's), if I remember correctly. Each number was stored internally as a significand, represented in BCD, and an exponent, just like an IEEE float, but for the change of representation of the significand. It was sort of a best-of-both worlds technique that allowed the calculators to avoid many of the binary representation hiccups that have been discussed in this thread, but still gave them a large range for calculations. If you're seriously interested in numerical work, studying these old calculators is really eye opening. They were remarkably well-engineered. I honestly wish I still had my old HP-15C. It was the best calculator I ever owned and only died sometime in the middle of college, circa 1988. :(
Cheers, Dave
Slowly but surely the world is finding Lisp. http://www.findinglisp.com/blog/

Post Reply