www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Float compare broke!

reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
  Most curiously while making unittests the asserts fail when I've 
confirmed it's working. The difference seems to be if it's 
immutable/const vs non, and why this makes a difference I don't 
see... Can someone give some light to this?

const float i_f = 3.14159265;
float a = i_f;
float b = i_f;
assert(a==b);    //passes
assert(a==i_f);  //fails
Jun 11 2012
next sibling parent "Matej Nanut" <matejnanut gmail.com> writes:
On Monday, 11 June 2012 at 10:33:22 UTC, Era Scarecrow wrote:
  Most curiously while making unittests the asserts fail when 
 I've confirmed it's working. The difference seems to be if it's 
 immutable/const vs non, and why this makes a difference I don't 
 see... Can someone give some light to this?

 const float i_f = 3.14159265;
 float a = i_f;
 float b = i_f;
 assert(a==b);    //passes
 assert(a==i_f);  //fails

Works for me. (Arch Linux x64, DMD from repositories, says the version is 2.059.)
Jun 11 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 11 June 2012 at 11:47:59 UTC, Matej Nanut wrote:
 On Monday, 11 June 2012 at 10:33:22 UTC, Era Scarecrow wrote:
 Most curiously while making unittests the asserts fail when 
 I've confirmed it's working. The difference seems to be if 
 it's immutable/const vs non, and why this makes a difference I 
 don't see... Can someone give some light to this?

 const float i_f = 3.14159265;
 float a = i_f;
 float b = i_f;
 assert(a==b);    //passes
 assert(a==i_f);  //fails

Works for me. (Arch Linux x64, DMD from repositories, says the version is 2.059.)

Hmmm I'm using 2.059 but for win32. Perhaps a 32bit specific bug or something else? I doubt it has anything to do with me running Win7 64bit...
Jun 11 2012
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
It probably has to do with different rounding
with the constant and the assignment.

http://dlang.org/float.html

Check out the section: Float­ing Point Con­stant Fold­ing

Dif­fer­ent com­piler set­tings, op­ti­miza­tion 
set­tings, and in­lin­ing set­tings can af­fect 
op­por­tu­ni­ties for con­stant fold­ing, there­fore the 
re­sults of float­ing point cal­cu­la­tions may dif­fer 
de­pend­ing on those set­tings.


a == b is probably done by the bits at runtime which match
because it is the same assignment.

But a == i_f might be propagated down there as 80 bit compared
to 32 bit and thus be just slightly different.



When comparing floating point you want to consider a little
wiggle room to be ok due to little rounding error. This function
should help:
http://dlang.org/phobos/std_math.html#approxEqual
Jun 11 2012
parent reply David <d dav1d.de> writes:
Am 11.06.2012 16:47, schrieb bearophile:
 Adam D. Ruppe:

 This function should help:
 http://dlang.org/phobos/std_math.html#approxEqual

This is better: http://dlang.org/phobos/std_math.html#feqrel Bye, bearophile

Wasn't there a bug with feqrel? I think so, that's the reason why I implemented almost_equal in gl3n: https://github.com/Dav1dde/gl3n/blob/master/gl3n/math.d#L80
Jun 11 2012
parent David <d dav1d.de> writes:
Am 11.06.2012 18:42, schrieb David:
 Am 11.06.2012 16:47, schrieb bearophile:
 Adam D. Ruppe:

 This function should help:
 http://dlang.org/phobos/std_math.html#approxEqual

This is better: http://dlang.org/phobos/std_math.html#feqrel Bye, bearophile

Wasn't there a bug with feqrel? I think so, that's the reason why I implemented almost_equal in gl3n: https://github.com/Dav1dde/gl3n/blob/master/gl3n/math.d#L80

Found it: Fixed: http://d.puremagic.com/issues/show_bug.cgi?id=5089
Jun 11 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 This function should help:
 http://dlang.org/phobos/std_math.html#approxEqual

This is better: http://dlang.org/phobos/std_math.html#feqrel Bye, bearophile
Jun 11 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 11 June 2012 at 12:54:37 UTC, Adam D. Ruppe wrote:
 a == b is probably done by the bits at runtime which match
 because it is the same assignment.

 But a == i_f might be propagated down there as 80 bit compared
 to 32 bit and thus be just slightly different.

Unfortunately I used FloatRep and printed out the exponent and fractions, and they were identical (false, 128, 4788187). Besides, shouldn't the same types do a direct bit-wise copy?
Jun 11 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 11 June 2012 at 20:28:06 UTC, Era Scarecrow wrote:
 On Monday, 11 June 2012 at 12:54:37 UTC, Adam D. Ruppe wrote:
 a == b is probably done by the bits at runtime which match
 because it is the same assignment.

 But a == i_f might be propagated down there as 80 bit compared
 to 32 bit and thus be just slightly different.

Unfortunately I used FloatRep and printed out the exponent and fractions, and they were identical (false, 128, 4788187). Besides, shouldn't the same types do a direct bit-wise copy?

Although re-reading your post it may make a little more sense... So I added a couple more tests.. Strangely the exact same issue is there while the rest aren't. The question then, is why the 32bit may be upgraded to an 80bit (if that indeed is happening)? But that doesn't make sense since the 80bit can hold identically anything the 32bit can hold and should still compare the same. -- const float i_f = 3.14159265; float a = i_f; float b = i_f; union fi { float f; ubyte[4] b; } fi c; c.b = [219, 15, 73, 64]; //bit for bit of the same value. float d = a; //float to float copy assert(a==b); //passes (float/float copied from const) assert(a==c.f); //passes (float/float union) assert(b==d); //passes (float/float) assert(a==i_f); //fails (float/const float)
Jun 11 2012
prev sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 11.06.2012 14:33, Era Scarecrow wrote:
 Most curiously while making unittests the asserts fail when I've
 confirmed it's working. The difference seems to be if it's
 immutable/const vs non, and why this makes a difference I don't see...
 Can someone give some light to this?

 const float i_f = 3.14159265;

a help of constfold-engine that prefers to keep precision intact (regardless of whether the type can actually hold it).
 float a = i_f;
 float b = i_f;
 assert(a==b); //passes
 assert(a==i_f); //fails

-- Dmitry Olshansky
Jun 11 2012