Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
March 19, 2012 Comparison issue | ||||
---|---|---|---|---|
| ||||
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 |
March 19, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to James Miller | 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
|
March 19, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile Attachments:
| 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 == among floating point values, and replace it with a library-defined function. > > Bye, > bearophile I wouldn't mind if it was just type weirdness, but its not. It appears that 1 does not equal 1. |
March 19, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Monday, 19 March 2012 at 12:50:02 UTC, 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.
>
> 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.
|
March 19, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 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. |
March 20, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | 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.
|
March 20, 2012 Re: Comparison issue | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don Clugston | 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 |
Copyright © 1999-2021 by the D Language Foundation