Ticket #4562: mc_paste_test02.txt

File mc_paste_test02.txt, 4.9 KB (added by newbie-02, 3 months ago)

File changed in pasting

Line 
1Comparing Floating Point Numbers, 2012 Edition
2Posted on February 25, 2012 by brucedawson
3This post is a more carefully thought out and peer reviewed version of a floating-point comparison article I wrote many years ago. This one gives solid advice and some surprising observations about the tricky subject of comparing floating-point numbers. A compilable source file with license is available.
4
5We’ve finally reached the point in this series that I’ve been waiting for. In this post I am going to share the most crucial piece of floating-point math knowledge that I have. Here it is:
6
7
8[Floating-point] math is hard.
9
10You just won’t believe how vastly, hugely, mind-bogglingly hard it is. I mean, you may think it’s difficult to calculate when trains from Chicago and Los Angeles will collide, but that’s just peanuts to floating-point math.
11
12Seriously. Each time I think that I’ve wrapped my head around the subtleties and implications of floating-point math I find that I’m wrong and that there is some extra confounding factor that I had failed to consider. So, the lesson to remember is that floating-point math is always more complex than you think it is. Keep that in mind through the rest of the post where we talk about the promised topic of comparing floats, and understand that this post gives some suggestions on techniques, but no silver bullets.
13
14Previously on this channel…
15This is the fifth chapter in a long series. The first couple in the series are particularly important for understanding this point. A (mostly) complete list of the other posts includes:
16
171: Tricks With the Floating-Point Format – an overview of the float format
182: Stupid Float Tricks – incrementing the integer representation
193: Don’t Store That in a Float – a cautionary tale about time
203b: They sure look equal… – ranting about Visual Studio’s float failings
214: Comparing Floating Point Numbers, 2012 Edition (return *this;)
225: Float Precision–From Zero to 100+ Digits – non-obvious answers to how many digits of precision a float has
236: C++ 11 std::async for Fast Float Format Finding – running tests on all floats in just a few minutes
247: Intermediate Floating-Point Precision – the surprising complexities of how expressions can be evaluated
258: Floating-point complexities – some favorite quirks of floating-point math
269: Exceptional Floating Point – using floating point exceptions for fun and profit
2710: That’s Not Normal–the Performance of Odd Floats – the performance implications of infinities, NaNs, and denormals
28(xn) −
29f((x))
30f11: Doubles are not floats, so don’t compare them – a common type of float comparison mistake
31(xn) −
32f((x))
33f12: Float Precision Revisited: Nine Digit Float Portability – moving floats between gcc and VC++ through text
34(xn) −
35f((x))
36f13: Floating-Point Determinism – what does it take to get bit-identical results
37(xn) −
38f((x))
39f14: There are Only Four Billion Floats–So Test Them All! – exhaustive testing to avoid embarrassing mistakes
40(xn) −
41f((x))
42f15: Please Calculate This Circle’s Circumference – the intersection of C++, const, and floats
43(xn) −
44f((x))
45f16: Intel Underestimates Error Bounds by 1.3 quintillion – the headline is not an exaggeration, but it’s not as bad as it sounds
46(xn) −
47f((x))
48fComparing for equality
49(xn) −
50f((x))
51fFloating point math is not exact. Simple values like 0.1 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations or the precision of intermediates can change the result. That means that comparing two floats to see if they are equal is usually not what you want. GCC even has a (well intentioned but misguided) warning for this: “warning: comparing floating point with == or != is unsafe”.
52(xn) −
53f((x))
54f
55(xn) −
56f((x))
57fHere’s one example of the inexactness that can creep in:
58(xn) −
59f((x))
60f
61(xn) −
62f((x))
63ffloat f = 0.1f;
64(xn) −
65f((x))
66ffloat sum;
67(xn) −
68f((x))
69fsum = 0;
70(xn) −
71f((x))
72f
73(xn) −
74f((x))
75ffor (int i = 0; i < 10; ++i)
76(xn) −
77f((x))
78f    sum += f;
79(xn) −
80f((x))
81ffloat product = f * 10;
82(xn) −
83f((x))
84fprintf("sum = %1.15f, mul = %1.15f, mul2 = %1.15f\n",
85(xn) −
86f((x))
87f        sum, product, f * 10);
88(xn) −
89f((x))
90fThis code tries to calculate ‘one’ in three different ways: repeated adding, and two slight variants of multiplication. Naturally we get three different results, and only one of them is 1.0:
91(xn) −
92f((x))
93f
94(xn) −
95f((x))
96fsum=1.000000119209290, mul=1.000000000000000, mul2=1.000000014901161
97(xn) −
98f((x))
99f
100(xn) −
101f((x))
102fDisclaimer: the results you get will depend on your compiler, your CPU, and your compiler settings, which actually helps make the point.
103(xn) −
104f((x))
105f
106(xn) −
107f((x))
108fSo what happened, and which one is correct?
109(xn) −
110f((x))
111f
112(xn) −
113f((x))
114fWhat do you mean ‘correct’?
115(xn) −
116f((x))
117f