Page 1 of 3

incorrect simple floating point math

Posted: Thu Jun 18, 2009 11:43 am
by speech impediment
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?

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 1:05 pm
by Tom
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

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 2:32 pm
by smithzv
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)))

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 3:36 pm
by speech impediment
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? ;-)

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 6:25 pm
by nuntius
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/

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 7:30 pm
by findinglisp
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.

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 8:16 pm
by gugamilare
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.

Re: incorrect simple floating point math

Posted: Thu Jun 18, 2009 9:43 pm
by simon
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.

Re: incorrect simple floating point math

Posted: Fri Jun 19, 2009 8:05 am
by Harleqin
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.

Re: incorrect simple floating point math

Posted: Fri Jun 19, 2009 9:13 am
by findinglisp
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. :(