Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 07, 2011 Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Hello! I've been programming some miscellaneous code and got stuck in an odd case. While comparing floats, two obviously identical values return false in comparison. I am not sure if this is related to float precision or something similar. This is the code that I have used: import std.stdio; void main(string[] args) { while(foo()) {} } bool foo() { static bool ss; static int loops; static float m = 0f; if(m != 1.73205f) { m += 0.00500592f; if(++loops == 346) ss = true; } if(ss) { writefln("Variable: %s", m); writefln("Constant: %s", 1.73205f); writefln("Equality: %s", m == 1.73205f); return false; } return true; } The output of this program is the following: Variable: 1.73205 Constant: 1.73205 Equality: false My question is; how come these values compare unequal? |
July 07, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Loopback | On Thu, 07 Jul 2011 20:19:05 +0200, Loopback <elliott.darfink@gmail.com> wrote: > Hello! > > I've been programming some miscellaneous code and got stuck in an odd > case. While comparing floats, two obviously identical values return > false in comparison. > > I am not sure if this is related to float precision or something > similar. This is the code that I have used: > > import std.stdio; > > void main(string[] args) > { > while(foo()) {} > } > > bool foo() > { > static bool ss; > static int loops; > static float m = 0f; > > if(m != 1.73205f) > { > m += 0.00500592f; > > if(++loops == 346) > ss = true; > } > > if(ss) > { > writefln("Variable: %s", m); > writefln("Constant: %s", 1.73205f); > writefln("Equality: %s", m == 1.73205f); > > return false; > } > > return true; > } > > The output of this program is the following: > > Variable: 1.73205 > Constant: 1.73205 > Equality: false > > My question is; how come these values compare unequal? Try adding this in there: writefln("Difference: %s", m - 1.73205); It prints: Difference: 1.61095e-06 It may also be worth using %a to see the actual values in a float: writefln("Variable: %a", m); writefln("Constant: %a", 1.73205f); Variable: 0x1.bb67bcp+0 Constant: 0x1.bb67ap+0 As you can see, these numbers are different. Floating point math is weird. Two numbers that look the same can be different. -- Simen |
July 07, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Loopback | On Thu, 07 Jul 2011 14:19:05 -0400, Loopback <elliott.darfink@gmail.com> wrote:
> Hello!
>
> I've been programming some miscellaneous code and got stuck in an odd
> case. While comparing floats, two obviously identical values return
> false in comparison.
>
> I am not sure if this is related to float precision or something
> similar. This is the code that I have used:
>
> import std.stdio;
>
> void main(string[] args)
> {
> while(foo()) {}
> }
>
> bool foo()
> {
> static bool ss;
> static int loops;
> static float m = 0f;
>
> if(m != 1.73205f)
> {
> m += 0.00500592f;
>
> if(++loops == 346)
> ss = true;
> }
>
> if(ss)
> {
> writefln("Variable: %s", m);
> writefln("Constant: %s", 1.73205f);
> writefln("Equality: %s", m == 1.73205f);
>
> return false;
> }
>
> return true;
> }
>
> The output of this program is the following:
>
> Variable: 1.73205
> Constant: 1.73205
> Equality: false
>
> My question is; how come these values compare unequal?
Because they aren't. Just because they are equal to 5 decimal places (which by the way is an inaccurate printout of their value), does not mean they are fully equal.
Be very careful when comparing floating point numbers. Generally you want to use an epsilon to say they are "close enough".
-Steve
|
July 08, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 2011-07-07 20:35, Steven Schveighoffer wrote:
> On Thu, 07 Jul 2011 14:19:05 -0400, Loopback <elliott.darfink@gmail.com>
> wrote:
>
>> Hello!
>>
>> I've been programming some miscellaneous code and got stuck in an odd
>> case. While comparing floats, two obviously identical values return
>> false in comparison.
>>
>> I am not sure if this is related to float precision or something
>> similar. This is the code that I have used:
>>
>> import std.stdio;
>>
>> void main(string[] args)
>> {
>> while(foo()) {}
>> }
>>
>> bool foo()
>> {
>> static bool ss;
>> static int loops;
>> static float m = 0f;
>>
>> if(m != 1.73205f)
>> {
>> m += 0.00500592f;
>>
>> if(++loops == 346)
>> ss = true;
>> }
>>
>> if(ss)
>> {
>> writefln("Variable: %s", m);
>> writefln("Constant: %s", 1.73205f);
>> writefln("Equality: %s", m == 1.73205f);
>>
>> return false;
>> }
>>
>> return true;
>> }
>>
>> The output of this program is the following:
>>
>> Variable: 1.73205
>> Constant: 1.73205
>> Equality: false
>>
>> My question is; how come these values compare unequal?
>
> Because they aren't. Just because they are equal to 5 decimal places
> (which by the way is an inaccurate printout of their value), does not
> mean they are fully equal.
>
> Be very careful when comparing floating point numbers. Generally you
> want to use an epsilon to say they are "close enough".
>
> -Steve
Thank you for your answers!
I do want to ask though what an alternative would be in this case, to
compare the two different values. You mentioned something about
"epsilons" but I have no experience within this field. I would really
appreciate an example or something similar so I could understand your
statement.
From what I can see these are two identical values, I would be more than
glad if someone could explain just what is the difference between these
two "non-equal" values and how make them "equal". Perhaps I should use
ints and long instead since they don't seem to suffer from this
"problem"?
|
July 08, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Loopback | Loopback: > I do want to ask though what an alternative would be in this case, to compare the two different values. You mentioned something about "epsilons" but I have no experience within this field. I would really appreciate an example or something similar so I could understand your statement. If you want to use floating point values in your programs then you probably need to know something about floating point representation. This is a good starting point: http://en.wikipedia.org/wiki/Floating_point For your problem there is the feqrel function: http://www.digitalmars.com/d/2.0/phobos/std_math.html#feqrel > From what I can see these are two identical values, I would be more than > glad if someone could explain just what is the difference between these > two "non-equal" values and how make them "equal". Perhaps I should use > ints and long instead since they don't seem to suffer from this > "problem"? Generally in a program you use floating point values only if you can't use integral values (and you don't want to go toward fixed point values, rationals, etc). Bye, bearophile |
July 08, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 2011-07-07 17:28, bearophile wrote: > Loopback: > > I do want to ask though what an alternative would be in this case, to compare the two different values. You mentioned something about "epsilons" but I have no experience within this field. I would really appreciate an example or something similar so I could understand your statement. > > If you want to use floating point values in your programs then you probably > need to know something about floating point representation. This is a good > starting point: http://en.wikipedia.org/wiki/Floating_point > For your problem there is the feqrel function: > http://www.digitalmars.com/d/2.0/phobos/std_math.html#feqrel > > > From what I can see these are two identical values, I would be more than > > > > glad if someone could explain just what is the difference between these two "non-equal" values and how make them "equal". Perhaps I should use ints and long instead since they don't seem to suffer from this "problem"? > > Generally in a program you use floating point values only if you can't use integral values (and you don't want to go toward fixed point values, rationals, etc). What Every Computer Scientist Should Know About Floating-Point Arithmetic: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html - Jonathan M Davis |
July 08, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 2011-07-08 02:28, bearophile wrote:
> Loopback:
>
>> I do want to ask though what an alternative would be in this case, to
>> compare the two different values. You mentioned something about
>> "epsilons" but I have no experience within this field. I would really
>> appreciate an example or something similar so I could understand your
>> statement.
>
> If you want to use floating point values in your programs then you probably need to know something about floating point representation. This is a good starting point:
> http://en.wikipedia.org/wiki/Floating_point
> For your problem there is the feqrel function:
> http://www.digitalmars.com/d/2.0/phobos/std_math.html#feqrel
>
>
>> From what I can see these are two identical values, I would be more than
>> glad if someone could explain just what is the difference between these
>> two "non-equal" values and how make them "equal". Perhaps I should use
>> ints and long instead since they don't seem to suffer from this
>> "problem"?
>
> Generally in a program you use floating point values only if you can't use integral values (and you don't want to go toward fixed point values, rationals, etc).
>
> Bye,
> bearophile
I've looked up both approxEqual and feqrel, and the last one seems most
appropriate, though I cannot use this function without issuing any
errors. If I use the following code:
writefln("Equality: %s", feqrel(m, 1.73205f));
(From the previous example)
I receive this error with the code:
Error: function std.math.feqrel!(float).feqrel has no return statement, but is expected to return a value of type int
Error: template instance std.math.feqrel!(float) error instantiating
|
July 09, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Loopback | On 2011-07-08 04:31, Loopback wrote: > On 2011-07-08 02:28, bearophile wrote: >> Loopback: >> >>> I do want to ask though what an alternative would be in this case, to >>> compare the two different values. You mentioned something about >>> "epsilons" but I have no experience within this field. I would really >>> appreciate an example or something similar so I could understand your >>> statement. >> >> If you want to use floating point values in your programs then you >> probably need to know something about floating point representation. >> This is a good starting point: >> http://en.wikipedia.org/wiki/Floating_point >> For your problem there is the feqrel function: >> http://www.digitalmars.com/d/2.0/phobos/std_math.html#feqrel >> >> >>> From what I can see these are two identical values, I would be more than >>> glad if someone could explain just what is the difference between these >>> two "non-equal" values and how make them "equal". Perhaps I should use >>> ints and long instead since they don't seem to suffer from this >>> "problem"? >> >> Generally in a program you use floating point values only if you can't >> use integral values (and you don't want to go toward fixed point >> values, rationals, etc). >> >> Bye, >> bearophile > I've looked up both approxEqual and feqrel, and the last one seems most > appropriate, though I cannot use this function without issuing any > errors. If I use the following code: > > writefln("Equality: %s", feqrel(m, 1.73205f)); > > (From the previous example) > > I receive this error with the code: > Error: function std.math.feqrel!(float).feqrel has no return statement, > but is expected to return a value of type int > Error: template instance std.math.feqrel!(float) error instantiating I weren't able to solve this error so if it's of anyone's interest I used this function instead; int feqrel(real a, real b) { if (a==b) return real.mant_dig; real diff = fabs(a-b); ushort *pa = cast(ushort *)(&a); ushort *pb = cast(ushort *)(&b); ushort *pd = cast(ushort *)(&diff); int bitsdiff = ( ((pa[4]&0x7FFF) + (pb[4]&0x7FFF)-1)>>1) - pd[4]; if (pd[4]== 0) { diff*=0x1p+63; return bitsdiff + real.mant_dig - pd[4]; } if (bitsdiff>0) return bitsdiff+1; return bitsdiff==0 ? pa[4]==pb[4] : 0; } From: http://www.digitalmars.com/d/archives/digitalmars/D/27873.html |
July 09, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to Loopback | Loopback:
> I weren't able to solve this error so if it's of anyone's interest I used this function instead;
If you think you have found a bug in Phobos, then I suggest you to add it to Bugzilla (with your working version too, if you want).
Bye,
bearophile
|
July 09, 2011 Re: Float Comparison Returns False | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | This has already been reported: http://d.puremagic.com/issues/show_bug.cgi?id=5089 David On 7/9/11 2:01 PM, bearophile wrote: > Loopback: > >> I weren't able to solve this error so if it's of anyone's interest I >> used this function instead; > > If you think you have found a bug in Phobos, then I suggest you to add it to Bugzilla (with your working version too, if you want). > > Bye, > bearophile |
Copyright © 1999-2021 by the D Language Foundation