8 ms·
Bitten by the floating point bug
- echaozh 14y agoIf it's 40.00000000001/0.00000000001, things may be different. But since it's just 40.1/0.1, why not just use round()? With such small error, round() should produce 4.
- deelowe 14y agoHe addresses this in the article. Something about cpu usage, yadda yadda. I'm curious as to how he can be so sure about performance though when fundamentally not understanding how floats and ints get converted to binary.
- MikeDucker 14y agoIt's because I'm using ints for position data to allow fast look-ups of nearby objects in a very simple 2D environment. It's not about the speed of the same calculations between floats and ints (if that's what you were wondering).
- niggler 14y agoA useful and relevant article: "What every computer scientist should know about floating-point arithmetic" -- he discusses how to use correction factors to address the problem. http://www.cse.msu.edu/~cse320/Documents/FloatingPoint.pdf http://www.cse.msu.edu/~cse320/Documents/FloatingPoint.pdf
- MikeDucker 14y agoThanks, that'll be very useful. I can quite blatantly do with learning more.
- kodablah 14y agoNon PDF: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.ht...
- monochromatic 14y agoThat is not a floating point bug. That is a programmer who doesn't grok floating point. edit: Also, I am only allowed to say this if OP is a guy. If OP is a girl and she gets insulted, I'll be hearing about it on the HN front page for days.
- lclarkmichalek 14y agoWhy the sexism? Seems rather uncalled for.
- monochromatic 14y agoPointing out a difference between the sexes isn't sexist. What I was referencing was this: http://news.ycombinator.com/item?id=5106767 http://news.ycombinator.com/item?id=5106767 And of course all the follow-on white-knighting that shitted up the HN front page for days afterward.
- scott_s 14y agoComparing the two situations is absurd. First, myself and several others in the thread did not realize the author behind that post was a woman until reading the comments. This was well after I had upvoted the article, and decided it was worth discussing. Second, that was a situation where someone said "what you made is crap." You are saying, "you don't understand floating point," which the author clearly cops to. And, to that point, I'm surprised there are several comments in this thread that say "the bug is in your code, not with floating point" when it was clear to me that this author knew that, he was just playing with words in his title.
- MikeDucker 14y agoI'm glad one person appreciates my main sin is ban punnery, with a minor in forgetting floating point gotchas. I feel like someone who just told an anecdote about a time they slipped over whilst running and now everyone assumes they never knew how to walk.
- 14y ago
- smoyer 14y agoThis isn't a bug ... you really need to understand how floating point numbers work if you're going to do ANYTHING with them. At one point, I wrote an entire single-precision IEEE compliant floating point library in assembly language and while that product failed (an embedded system), it's been invaluable in the 20 years since that project. When working with higher level languages, I completely understand how my numbers will be rounded, precision truncated, etc. Casting back and forth to integers is often problematic, but even more telling is that the programs that have to be very precise generally use fixed-point integers. Banking and accounting don't tend to like single "pixel" rounding errors!
- toyg 14y agoBanking and accounting don't tend to like single "pixel" rounding errors! Working in the field, I was actually shocked by how much people freely round up a million here and a million there, more often than not in official reports for the board and/or financial authorities. You wouldn't believe how many times I had to show floating-point "errors" in Excel, leaving young accountants close to tears. They only care about numbers "looking the same" and being able to justify most discrepancies.
- acqq 14y agoCorrect. Not the bug of the floating point hardware. Floating point hardware which implements IEEE does what it is supposed to do. It's a "PEBKAC." Moreover, if OP understood the subject a little better, he'd know that 123 is stored exactly. Specifically, 123 is in binary 1111011. When stored in IEEE format you'll see in the mantissa bits the exact match: 111011 (the first bit is implicit). You can check it here: http://www.h-schmidt.net/FloatConverter/IEEE754.html http://www.h-schmidt.net/FloatConverter/IEEE754.html OP was bitten by assuming that decimal parts have exact representation, whereas from .1 to .9 only .5 has. Once he divides the exact 123 with the exact 10 he has to have 12.3 stored in the register, 12.3 has an infinite number of bits in the given representation and they have to be cut somewhere to fit any finite storage: 10001(0011)... If you check with the same converter, IEEE is careful enough to even know that after last 00 bits that fit in the 64-bits two 11 follow, so what's stored is 01 instead 00 for the last digits. The only solution for people who don't understand all the pitfalls of the standardized binary representation would be using base-10 floating point which is also standardized but sadly the last time I've checked existed only in some IBM hardware: http://en.wikipedia.org/wiki/IEEE_floating_point http://en.wikipedia.org/wiki/IEEE_floating_point (see IEEE 754-2008) The software support is equivalently rare.
- zvrba 14y ago> "The problem this has is that the number 4 might be stored as 3.999999992 and if you cast that to an int naively you could end up with the integer value being 3 rather than 4. " No it might not. The author completely misunderstands FP.
- MikeDucker 14y agoAre you saying that a floating point value just under 4 won't necessarily cast to 3 or something else? (I'm reading the above posted links, but am intrigued at what I've gotten wrong with my statement you quoted)
- monochromatic 14y ago4 is represented exactly. (But 0.4 isn't.)
- MikeDucker 14y agoAh, I see. I'll update my post. Thanks.
- scott_s 14y agoMore pernicious is you may think that the result of a computation should be an exact number, but it may not be. Consider: #include "stdio.h" int main() { double num = 3.0; unsigned long long i; for (i = 0; i < 1000000000; ++i) { num += 1e-9; } printf("%f\n", num); printf("%llx\n", *((unsigned long long*)&num)); double four = 4.0; printf("%f\n", four); printf("%llx\n", *((unsigned long long*)&four)); return 0; } And then executed, [scott_s@local ~] ./float 4.000000 40100000058d7800 4.000000 4010000000000000
- 0x0 14y agoWould it have helped to use, for example, 0.0625 or 0.125 as the scaling factor, instead of 0.1?
- mturmon 14y agoExactly! Scale by a power of two and most of these surprises will go away. 0.1 is particularly problematic because it happens not to be exactly representable as an IEEE FP number, or even as a finite-length binary sequence (http://www.wolframalpha.com/input/?i=0.1+to+binary http://www.wolframalpha.com/input/?i=0.1+to+binary). So taking exact numbers and multiplying them by this scale factor will tend to produce inexact numbers, which when truncated, will cause surprises. Even scaling by something closer to a power of two would be better (1/16 + 1/32 = 0.09375).
- loeg 14y agoTl;dr: Use int i = round(f); instead of: int i = (int)f;