Thread overview
Float compare broke!
Jun 11, 2012
Era Scarecrow
Jun 11, 2012
Matej Nanut
Jun 11, 2012
Era Scarecrow
Jun 11, 2012
Adam D. Ruppe
Jun 11, 2012
bearophile
Jun 11, 2012
David
Jun 11, 2012
David
Jun 11, 2012
Era Scarecrow
Jun 11, 2012
Era Scarecrow
Jun 11, 2012
Dmitry Olshansky
June 11, 2012
 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
June 11, 2012
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.)
June 11, 2012
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...
June 11, 2012
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
June 11, 2012
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
June 11, 2012
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
June 11, 2012
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

June 11, 2012
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?
June 11, 2012
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)
June 11, 2012
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;
Doesn't fit into float AFAIK. The rest "flows" naturally from here with 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