views:

480

answers:

7

(int)(33.46639 * 1000000) returns 33466389

Why does this happen?

+5  A: 

Double precision is not exact, so internally 33.46639 is actually stored as 33.466389

Edit: As Richard said, it's floating point data, (stored in binary in a finite set of bits) so it's not exactly that) ....

Milan Ramaiya
or 33.4668885 or something else 'close enough' that rounds to it, depending on the hardware.
DaveE
Um, none of the above. It's in base 2. Most such numbers CANNOT be expressed exactly in base 10. (Without resorting using infinitely-repeating digit sequences, anyway. Similar to how 1/3 must be represented as 0.33333[inf] in base 10.)
Richard Berg
Fair enough, not exactly that ... but something closer to that than the original one.
Milan Ramaiya
@Richard: **Wrong**. _Any_ base 2 number can be expressed exactly as a non-repeating decimal in base ten. (Because ten is a multiple of two)
SLaks
For what it's worth, here's the IEEE spec on storing FP data. http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/proguide/ref/rvimaebf.htm You guys read it and fight over it. I'm not going to.
Milan Ramaiya
FWIW, it's exactly `33.46638999999999697365637985058128833770751953125`.
Stephen Canon
@Richard Berg: Most real numbers cannot be expressed in floating point. All numbers that can be expressed exactly with N bits to the right of the decimal (binary?) point can be expressed exactly with N digits to the right of the decimal point.
David Thornley
@SLaks - you're right. Floats are of the form *Ax2^B*. My first intuition was that negative values of *B* would yield repeating decimals in other bases -- which is true for some bases, but not for base 10 [and other "even" bases]. Clearly *1/2, 1/4, 1/8,* etc all have exact decimal representations. The set of decimals is closed under multiplication, so *A/2, A/4, A/8...* are also representable, QED.
Richard Berg
@David - I don't quite follow. Proving that exact decimals in base X are also exact decimals in base Y does require a constraint (divisibility). And the # of digits certainly isn't constant between bases.
Richard Berg
+30  A: 

Floating point math isn't perfect. What every programmer should know about it.

Floating-point arithmetic is considered an esoteric subject by many people. This is rather surprising because floating-point is ubiquitous in computer systems. Almost every language has a floating-point datatype; computers from PCs to supercomputers have floating-point accelerators; most compilers will be called upon to compile floating-point algorithms from time to time; and virtually every operating system must respond to floating-point exceptions such as overflow. This paper presents a tutorial on those aspects of floating-point that have a direct impact on designers of computer systems. It begins with background on floating-point representation and rounding error, continues with a discussion of the IEEE floating-point standard, and concludes with numerous examples of how computer builders can better support floating-point.

...

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation.

Richard Berg
It's true that floating-point arithmetic is both ubiquitous and complicated, but this doesn't answer the question (unless you count linking to an 80-page paper that has the answer somewhere).
Henry Jackson
@Henry - the point is in the title of the linked article. **Every** programmer should know about this, and if they don't they should read the article. (OK, maybe not all 80 pages ...)
Stephen C
+1: linking to an 80-page paper that has the answer somewhere is a the standard anwser. This question -- in one form or another -- gets asked way too frequently. This paper is *the* answer. The questions are all duplicates. We don't need to repeat this information again and again.
S.Lott
+1 I agree @S.Lott, The link to that article is THE answer.
Pwninstein
A: 

The reason you got a different result is the fact that you used a 'cast'

(int)(33.46639 * 1000000) returns 33466389
^^^^^

to cast the result to a type of 'int'... which either rounded up or down the integral type when multipled together and then converted to 'int'.... do not rely on floating point to be accurate enough....Skeet posted an excellent introduction on his site here and here...

tommieb75
There's nothing inherently lossy about a cast. Arbitrary-precision libraries exist.
Richard Berg
I'd imagine he's asking "where did the 8 come from in my result?" Multiplying by 1000000 is like moving the decimal 6 places to the right, which should be "33466390", but that's not what he's getting. Your answer is what I thought initially though, until I read the question again.
Pwninstein
@Richard - coercing a `float` or `double` value to an `int` discards the fractional part, so you do lose information.
Seth
Seth, that's correct. What I'm saying is, truncation is a particular feature of float/double (via the CLI spec). It's not **inherent** to the C# cast operator, as Tommie seemed to imply.
Richard Berg
+1  A: 

If you're asking why it doesn't become 33466390, it's because doubles do not have infinite precision, and the number cannot be expressed exactly in binary.

If you replace the double with a decimal ((int)(33.46639m * 1000000)), it be equal to 33466390, because decimals are calculated in base 10.

SLaks
Problems like these are inherent in floating-point, not just binary floating point. Sure, decimal gets 33.46639*1000000 right, but still has 1/3*3 != 1 and pow(sqrt(2), 2) != 2.
dan04
Yes, but his specific problem is due to binary.
SLaks
+2  A: 

The reason is that 33.46639 will be represented as something slightly less than that number.

Multiplying by 1000000 will give you 33466389.99999999.

Type-casting using (int) will then just return the integer part (33466389).

If you want the "right" number, try round() before type casting.

Peter K.
Whoa! ..... no no no no no. If you want the "right" answer, you can't use floating point arithmetic.
Milan Ramaiya
No. If you want the "right" answer, you can't use *binary* floating point arithmetic. Use the `decimal` type which uses decimal floating point arithmetic and it will work as you expect.
Gabe
33.46639 is the "right" answer. The problem is that the questioner isn't asking the right question.
Stephen Canon
@gabe: I was assuming C, not C#. It's not clear from the question.
Peter K.
`decimal` type also has problems, albeit for other numbers. Any number system with a fixed number of "bits" can only represent a finite set of numbers, and there are infinitely many real numbers between any two numbers.
Alok
Peter: I was responding to Gonzo, who said you can't use floating point arithmetic. I used `decimal` as an example of a floating point type that will give the correct answer.
Gabe
@gabe: Understood! Thanks for the clarification.
Peter K.
@Reverend Gonzo: The reason my answer had right in "" was precisely for your issue. It's like the tourist in Ireland who stops a farmer in the middle of nowhere asking for directions. T: "Do you know where place X is?" F: "I do." T: "How do I get there?"F: "Well I wouldn't be starting from here."
Peter K.
+1  A: 

Because 33.46639 can't be expressed exactly in a finite number of binary digits. The actual result of 33.46639 * 1000000 is 33466389.9999999962747097015380859375. The cast truncates it to 33466389.

dan04
Try "can't be expressed exactly in a finite number of fractional binary digits"
Ben Voigt
+3  A: 

It was New Years' Eve at the end of 1994. Andy Grove, CEO of Intel, was coming off a great year, what with the Pentium processor coming out and being a big hit. So, he walked into a bar and ordered a double shot of Johnnie Walker Green Label.

The bartender served it up and said, "that will be $20, sir."

Grove put a twenty dollar bill on the counter, looked at it for a moment, and said, "keep the change."

http://en.wikipedia.org/wiki/Pentium_FDIV_bug

Ollie Jones