on a floating-point equality exercise
a reply-to-all from the COMP1511 forums, 2017-09-10
(I’ve been asked several times about how to do this, so here’s my official “all the bells-and-whistles” answer.)
Many of you have found that your apparently-correct myAtoD
causes an
assertion failure, because the value you’ve produced (typically
something like -0.14100000000000001) isn’t exactly -0.141. As is the
way with floating-point numbers, you’re off by a tiny, tiny fraction.
The problem with floating-point numbers is that they’re not exact
values, but a finite number of approximations of real numbers.
Inherently, two numbers that appear the same aren’t guaranteed to have
exactly the same pattern of bits set to represent that floating-point
number. C’s equality operator, ==
, does bit-for-bit comparison, so two
floating-point numbers won’t always compare equal.
If I make a quick side-step to COMP1521 material: -0.141 actually
becomes -0.140999999999999986455279, which is stored as the bit pattern
0xBFC20C49BA5E353F
. The number you’re seeing is somewhere around
-0.141000000000000014210855, which is stored as the bit pattern
0xBFC20C49BA5E3540
.
0xBFC20C49BA5E353F
!= 0xBFC20C49BA5E3540
On my system, when I go to compile the extract.c
provided, I get a
compiler warning for this exact reason:
extract.c:25:19: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]
assert (dat.y == -0.141);
~~~~~ ^ ~~~~~~
One student on the forums has suggested that multiplying and dividing by 1000 produces a reasonable result. That might work… if there’s only three decimal places.
The way I’d do it is to explicitly check that the value is within a
range – that -0.142 < dat.y && dat.y < -0.140
. You might like to
write a function to do this.
If you’re interested in how numbers work, I highly recommend:
-
“What Every Computer Scientist Should Know About Floating-Point Numbers”
(David Goldberg, in ACM’s Computing Surveys, March 1991)
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html -
“How to Read Floating-Point Numbers Accurately”
(William D. Clinger, in the proceedings of the 1990 ACM Conference on Programming Language Design and Implementation)
http://www.cesura17.net/~will/Professional/Research/Papers/howtoread.pdf -
“How to Print Floating-Point Numbers Accurately”
(Guy L. Steele, Jon L. White; in the proceedings of the 1990 ACM Conference on Programming Language Design and Implementation)
https://lists.nongnu.org/archive/html/gcl-devel/2012-10/pdfkieTlklRzN.pdf