Live data from Hacker News

It's OK to compare floating-points for equality

lisyarus.github.io

81–90 of 150 posts

Re: It's OK to compare floating-points for equality

#81
post #22

Think about this. It's silly to use floating point numbers to represent geometry, because it gives coordinates closer to the origin more precision and in most cases the origin is just an arbitrary point.

Random aside but as I recall I think this is what made Kerbal Space Program so difficult. Very large distances and changing origins as you'd go to separate bodies, and I think the latter was basically because of this aspect of floating point. And because of the mismanagement of KSP2 they had to relearn these difficulties, because they didn't really have the experienced people work with the new developers. I only play…

What KSP really should have done is just done their orbital math separately from their force propagation. If they had made a virtual node for each craft's center of mass, they could have made it so that the COM position was just never affected by intra-body forces and done the orbital math in super high (Float128?) precision.

Re: It's OK to compare floating-points for equality

#82

Earlier quoted context omitted.

What you say was true exactly only in most floating-point formats that were used before 1980. In those old FP formats, the product of the smallest normalized and non-null FP number with the biggest normalized and non-infinite FP number was approximately equal to 1. However in the IEEE standard for FP arithmetic, it was decided that overflows are more dangerous than underflows, so the range of numbers greater than 1 h…

> With IEEE FP numbers, the product of the smallest and biggest non-null non-infinite numbers is no longer approximately 1, but it is approximately 4. This is just wrong? The largest Float64 is 1.7976931348623157e308 and the smallest is 5.0e-324 They multiply to ~1e-16.

>the smallest is 5.0e-324

That's a subnormal [1]. The smallest normal double is 2.22507e-308:

  DBL_MIN          = 2.22507e-308
  DBL_TRUE_MIN     = 4.94066e-324
[1] https://en.wikipedia.org/wiki/Subnormal_number

Re: It's OK to compare floating-points for equality

#83
post #22

Think about this. It's silly to use floating point numbers to represent geometry, because it gives coordinates closer to the origin more precision and in most cases the origin is just an arbitrary point.

You are right, but only for a certain meaning of the word "geometry". If "geometry" refers to the geometry of an affine space, i.e. a space of points, then indeed there is nothing special about any point that is chosen as the origin and no reason do desire lower tolerances for the coordinates of points close to the current origin. Therefore for the coordinates of points in an affine space, using fixed-point numbers w…

Fixed point and Floating point are extremely similar, so most of the time you should just go with floats. If you start with a fixed type, reserve some bits for storing an explicit exponent and define a normalization scheme, you've recreated the core of IEEE floats. That also means we can go the other way and emulate (lower precision) fixed point by masking an appropriate number of LSBs in the significand to regain the constant density of fixed. You can treat floating point like fixed point in a log space for most purposes, ignoring some fiddly details about exponent boundaries.

And since they're essentially the same, there just aren't many situations where implementing your own fixed point is worth it. MCUs without FPUs are increasingly uncommon. Financial calculations seem to have converged on Decimal floating point. Floating point determinism is largely solved these days. Fixed point has better precision at a given width, but 53 vs 64 bits isn't much different for most applications. If you happen to regularly encounter situations where you need translation invariants across a huge range at a fixed (high) precision though, fixed point is probably more useful to you.

Re: It's OK to compare floating-points for equality

#84
post #2

There is another way to compare floats for rough equality that I haven't seen much explored anywhere: bit-cast to integer, strip few least significant bits and then compare for equality. This is agnostic to magnitude, unlike epsilon which has to be tuned for range of values you expect to get a meaningful result.

This is essentially ULP (units in the last place) comparison, and it's a solid approach. One gotcha: IEEE 754 floats have separate representations for +0 and -0, so values straddling zero (like 1e-45 and -1e-45) will look maximally far apart as integers even though they're nearly equal. You need to handle the sign bit specially.

There's another gotcha. Consider positive, normal x and y where ulp(y) != ulp(x). Bitwise comparison, regardless of tolerance, will consider x to be far from y, even though they might be adjacent numbers, e.g. if y = x+ulp(x) but y is a power of 2.

Re: It's OK to compare floating-points for equality

#85
Well, at least the author is honest about it:

> The title of this post is an intentional clickbait.

Unfortunately, that's where the honesty ends.

> It's NOT OK to compare floating-points using epsilons.

> So, are epsilons good or bad? Usually bad, but sometimes okay.

So which is it? Emphatically NOT OK, or sometimes okay?

Re: It's OK to compare floating-points for equality

#86
post #7

I have this floating-point problem at scale and will donate $100 to the author, or to anyone here, who can improve my code the most. The Rust code in the assert_f64_eq macro is: if (a >= b && a - b I'm the author of the Rust assertables crate. It provides floating-point assert macros much as described in the article. https://github.com/SixArm/assertables-rust-crate/blob/main/s... If there's a way to make it more prec…

[deleted]

Re: It's OK to compare floating-points for equality

#87
post #7

I have this floating-point problem at scale and will donate $100 to the author, or to anyone here, who can improve my code the most. The Rust code in the assert_f64_eq macro is: if (a >= b && a - b I'm the author of the Rust assertables crate. It provides floating-point assert macros much as described in the article. https://github.com/SixArm/assertables-rust-crate/blob/main/s... If there's a way to make it more prec…

Author says in the article that for tests, and assertion is a test, it's ok to use epsilon.

Re: It's OK to compare floating-points for equality

#88

> In reality it is a pretty deterministic (modulo compiler options, CPU flags, etc) IIRC this was not ALWAYS the case, on x86 not too long ago the CPU might choose to put your operation in an 80-bit fp register, and if due to multitasking the CPU state got evicted, it would only be able to store it in a 32-bit slot while it's waiting to be scheduled back in? It might not be the case now in a modern system if based on…

I was bit by this years ago when our test cases failed on Linux, but worked on macos. pdftotext was behaving differently (deciding to merge two lines or not) on the two platforms - both were gcc and intel at the time. When I looked at it in a debugger or tried to log the values, it magically fixed itself.

Eventually I learned about the 80-bit thing and that macos gcc was automatically adding a -ffloat-store to make == more predictable (they use a floats everywhere in the UI library). Since pdftotext was full of == comparisons, I ended up adding a -ffloat-store to the gcc command line and calling it a day.

Re: It's OK to compare floating-points for equality

#89
post #22

Think about this. It's silly to use floating point numbers to represent geometry, because it gives coordinates closer to the origin more precision and in most cases the origin is just an arbitrary point.

For geometry, fixed-precision integers are better. But for computation and usability, floats are great. Scaling a 10 meter model in floats to 13% of the size is a trivial multiplication by 0.13f. With integers, this can get tricky. Can't first divide by 100 then multiply by 13 because you'd lose precision. Also can't multiply by 13 and then divide by 100 because you might overflow. Unless maybe venders would add hardware that computes that more accurately like they currently do for float, but honestly, float is good enough and the the potential benefits do not outweigh the disadvantages.

Float is also fantastic for depth values precisely because they have more precision towards the origin, basically quasi-logarithmic precision. Having double the precision at half the distance is A+. At least if you're writing software rasterizers and do linear depth. The story with depth buffer precision in GPU pipelines with normalized depth and and hyperbolic distribution is...sad.

Re: It's OK to compare floating-points for equality

#90

If your code may be compiled, to use the Intel x87 numerical coprocessor, an important issue is the so called "excess precision": Different values on chip can collapse after being rounded and stored to their memory locations, invalidating previous comparisons. Spilling can happen unexpectedly. Note that Intel calls the x87 "legacy"

Nobody's code will be compiled to use x87 any more.

There is plenty of demand for so called "secure code", where such coder arrogance will not be tolerated. Trust me on that, I know it.
Post reply on HN