## digitalmars.D.learn - Comparison issue

- James Miller <james aatch.net> Mar 19 2012
- bearophile <bearophileHUGS lycos.com> Mar 19 2012
- Don Clugston <dac nospam.com> Mar 20 2012
- James Miller <james aatch.net> Mar 19 2012
- "Jesse Phillips" <jessekphillips+D gmail.com> Mar 19 2012
- "H. S. Teoh" <hsteoh quickfur.ath.cx> Mar 19 2012

Hey, I'm trying to do some vector based code, and my unittests started to fail on testing normalize. I'm using the standard algorithm, but the assert is always return false. I did some investigation, and can show that this program causes failure: import std.math : sqrt; import std.stdio : writeln; T size(T)(T[] t){ T val = 0; for(size_t i = 0; i < t.length; i++) { val += t[i]*t[i]; } return sqrt(val); } void normalize(T)(ref T[] t) { auto s = size(t); foreach(ref v; t) { v /= s; } } void main() { float[] vector = [1,2,3,4]; normalize(vector); auto v1 = size!float(vector); writeln(v1 == 1); //false writeln(v1 == 1.0); //false writeln(v1 == 1.0f); //false writeln(v1+1 == 2.0f); //true } I used typeid and can show that the type of `v1` is `float`, as you'd expect. And the last one passes fine, as does doing `(v1+1)-1 == 1`. I'm not sure what could be causing this. I believe it may be a bug, but I would like to see if I'm just wrong instead. -- James Miller

Mar 19 2012

James Miller:writeln(v1 == 1); //false writeln(v1 == 1.0); //false writeln(v1 == 1.0f); //false writeln(v1+1 == 2.0f); //true

Maybe I'd like to deprecate and then statically forbid the use of == among floating point values, and replace it with a library-defined function. Bye, bearophile

Mar 19 2012

On 19/03/12 15:45, H. S. Teoh wrote:On Mon, Mar 19, 2012 at 08:50:02AM -0400, bearophile wrote:James Miller:writeln(v1 == 1); //false writeln(v1 == 1.0); //false writeln(v1 == 1.0f); //false writeln(v1+1 == 2.0f); //true

Maybe I'd like to deprecate and then statically forbid the use of == among floating point values, and replace it with a library-defined function.

I agree. Using == for any floating point values is pretty much never right. Either we should change the definition of == for floats to use abs(y-x)<epsilon for some given epsilon value, or we should prohibit it altogether, and force people to always write abs(y-x)<epsilon.

No, no, no. That's nonsense. For starters, note that ANY integer expression which is exact, is also exact in floating point. Another important case is that if (f == 0) is nearly always correct.Using == to compare floating point values is wrong. Due to the nature of floating point computation, there's always a possibility of roundoff error. Therefore, the correct way to compare floats is: immutable real epsilon = 1.0e-12; // adjustable accuracy here if (abs(y-x)< epsilon) { // approximately equal } else { // not equal }

And this is wrong, if y and x are both small, or both large. Your epsilon value is arbitrary. Absolute tolerance works for few functions like sin(), but not in general. See std.math.feqrel for a method which gives tolerance in terms of roundoff error, which is nearly always what you want. To summarize: For scientific/mathematical programming: * Usually you want relative tolerance * Sometimes you want exact equality. * Occasionally you want absolute tolerance But it depends on your application. For graphics programming you probably want absolute tolerance in most cases.

Mar 20 2012

On 03/20/2012 02:08 AM, Don Clugston wrote:For starters, note that ANY integer expression which is exact, is also exact in floating point.

With the note that the integer type has better precision at higher values. For example, there are many 32-bit values that uint can, but float cannot represent. Ali

Mar 20 2012

--0015175cac780b8ec604bb992a4b Content-Type: text/plain; charset=UTF-8 On Mar 20, 2012 1:50 AM, "bearophile" <bearophileHUGS lycos.com> wrote:James Miller:writeln(v1 == 1); //false writeln(v1 == 1.0); //false writeln(v1 == 1.0f); //false writeln(v1+1 == 2.0f); //true

Maybe I'd like to deprecate and then statically forbid the use of ==

Bye, bearophile

I wouldn't mind if it was just type weirdness, but its not. It appears that 1 does not equal 1. --0015175cac780b8ec604bb992a4b Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <p>On Mar 20, 2012 1:50 AM, "bearophile" <<a href=3D"mailto:be= arophileHUGS lycos.com">bearophileHUGS lycos.com</a>> wrote:<br> ><br> > James Miller:<br> ><br> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 writeln(v1 =3D=3D 1); //false<br> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 writeln(v1 =3D=3D 1.0); //false<br> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 writeln(v1 =3D=3D 1.0f); //false<br> > > =C2=A0 =C2=A0 =C2=A0 =C2=A0 writeln(v1+1 =3D=3D 2.0f); //true<br> ><br> > Maybe I'd like to deprecate and then statically forbid the use of = =3D=3D among floating point values, and replace it with a library-defined f= unction.<br> ><br> > Bye,<br> > bearophile</p> <p>I wouldn't mind if it was just type weirdness, but its not. It appea= rs that 1 does not equal 1.<br> </p> --0015175cac780b8ec604bb992a4b--

Mar 19 2012

On Monday, 19 March 2012 at 12:50:02 UTC, bearophile wrote:James Miller:

Maybe I'd like to deprecate and then statically forbid the use of == among floating point values, and replace it with a library-defined function. Bye, bearophile

I feel I should expand on bearophile's statement here. Checking for equality in a float is usually wrong. After performing operations on a float the accuracy if the number changes. So performing any operations could result in your result being off by a fraction I.e. v1 could be (I'm not being acurate here as to what it, print it out and see) 1.0000000000000000000001 0.9999999999999999999987 I think there is a std.math function called frequal or something.

Mar 19 2012

On Mon, Mar 19, 2012 at 08:50:02AM -0400, bearophile wrote:James Miller:

Using == to compare floating point values is wrong. Due to the nature of floating point computation, there's always a possibility of roundoff error. Therefore, the correct way to compare floats is: immutable real epsilon = 1.0e-12; // adjustable accuracy here if (abs(y-x) < epsilon) { // approximately equal } else { // not equal }Maybe I'd like to deprecate and then statically forbid the use of == among floating point values, and replace it with a library-defined function.

I agree. Using == for any floating point values is pretty much never right. Either we should change the definition of == for floats to use abs(y-x)<epsilon for some given epsilon value, or we should prohibit it altogether, and force people to always write abs(y-x)<epsilon. T -- Never step over a puddle, always step around it. Chances are that whatever made it is still dripping.

Mar 19 2012