views:

209

answers:

6

Possible Duplicate:
Dealing with accuracy problems in floating-point numbers

I was quite surprised why I tried to multiply a float in C (with GCC 3.2) and that it did not do as I expected.. As a sample:

int main() {
  float nb = 3.11f;
  nb *= 10;
  printf("%f\n", nb);
}

Displays: 31.099998

I am curious regarding the way floats are implemented and why it produces this unexpected behavior?

+13  A: 

First off, you can multiply floats. The problem you have is not the multiplication itself, but the original number you've used. Multiplication can lose some precision, but here the original number you've multiplied started with lost precision.

This is actually an expected behavior. floats are implemented using binary representation which means they can't accurately represent decimal values.

See MSDN for more information.

You can also see in the description of float that it has 6-7 significant digits accuracy. In your example if you round 31.099998 to 7 significant digits you will get 31.1 so it still works as expected here.

double type would of course be more accurate, but still has rounding error due to it's binary representation while the number you wrote is decimal.

If you want complete accuracy for decimal numbers, you should use a decimal type. This type exists in languages like C#. http://msdn.microsoft.com/en-us/library/system.decimal.aspx

You can also use rational numbers representation. Using two integers which will give you complete accuracy as long as you can represent the number as a division of two integers.

brickner
Great explanation, thanks!
Dpp
read also read also http://en.wikipedia.org/wiki/IEEE_754-2008 , http://grouper.ieee.org/groups/754/ and http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=4610935 (if you can be a subscriber...)
ShinTakezou
+5  A: 

This is working as expected. Computers have finite precision, because they're trying to compute floating point values from integers. This leads to floating point inaccuracies.

The Floating point wikipedia page goes into far more detail on the representation and resulting accuracy problems than I could here :)

Interesting real-world side-note: this is partly why a lot of money calculations are done using integers (cents) - don't let the computer lose money with lack of precision! I want my $0.00001!

Stephen
*"... don't let the computer lose money with rounding errors! I want my $0.00001"*. Integer calculations don't prevent rounding errors. (What is the exact integer representation of `$10/3` ???) They just make them easier for non-computer literate folks to accept.
Stephen C
@Stephen C: Thanks, clarified.
Stephen
It's true that you can't do exact *division* without rational arithmetic. But storing amounts in cents provides exact *representation*, as well as exact addition, subtraction, and multiplication by integers.
dan04
in general other "representation" are used for financial mathematics (preserving only two decimal digits often is not enough); this is another interesting reading for who's interested in such problems: http://speleotrove.com/decimal/decifaq1.html
ShinTakezou
+1  A: 

From Wikipedia article:

The fact that floating-point numbers cannot precisely represent all real numbers, and that floating-point operations cannot precisely represent true arithmetic operations, leads to many surprising situations. This is related to the finite precision with which computers generally represent numbers.

qrdl
+2  A: 

In the Python communities we often see people surprised at this, so there are well-tested-and-debugged FAQs and tutorial sections on the issue (of course they're phrased in terms of Python, not C, but since Python delegates float arithmetic to the underlying C and hardware anyway, all the descriptions of float's mechanics still apply).

It's not the multiplication's fault, of course -- remove the statement where you multiply nb and you'll see similar issues anyway.

Alex Martelli
A: 

Floating points are not precise because they use base 2 (because it's binary: either 0 or 1) instead of base 10. And base 2 converting to base 10, as many have stated before, will cause rounding precision issues.

thyrgle
Any base you choose will give you rounding precision issues. It's just we're used to those associated with base 10 (quick: what's the precise value of 1 divided by 3?) and not to those associated with base 2.
JUST MY correct OPINION
@JUST MY correct OPINION: Yeah, they would all give imprecise values. And so does base 2, and since floats use base 2 that is why I am using it in my answer. Also, when you convert from an one base to another base you get precision lost.
thyrgle
It's important to note that rounding precision issues do exist in decimal. For example, in Python, Decimal(1) / 3 * 3== Decimal('0.9999999999999999999999999999'), and Decimal(2).sqrt() ** 2 == Decimal('1.999999999999999999999999999').
dan04
Base 2 is actually *more* precise than base 10. On computers, numbers ultimately have to be stored in binary, and using another base requires making some bit patterns unavailable to represent numbers. Furthermore, the "hidden bit" trick that adds 1 bit of precision is unique to binary.The only disadvantage of binary is that it can't represent exact *decimal* values like monetary amounts.
dan04
@dan04: Still, the conversion results to accuracy lost. Even if base 2 is more accurate.
thyrgle
+4  A: 

The number 3.11 cannot be represented in binary. The closest you can get with 24 significant bits is 11.0001110000101000111101, which works out to 3.1099998950958251953125 in decimal.

If your number 3.11 is supposed to represent a monetary amount, then you need to use a decimal representation.

dan04