Jump to page: 1 2
Thread overview
What am I doing wrong here - canFind with iota is not working
Feb 26, 2015
Kingsley
Feb 26, 2015
John Colvin
Feb 26, 2015
John Colvin
Feb 26, 2015
Laeeth Isharc
Feb 26, 2015
bearophile
Feb 27, 2015
bearophile
Feb 26, 2015
John Colvin
Feb 26, 2015
Laeeth Isharc
Feb 26, 2015
Baz
Feb 26, 2015
Kingsley
Feb 26, 2015
Kingsley
Feb 26, 2015
Fool
Feb 26, 2015
Baz
February 26, 2015
float oneDegree = (PI / 180.0);
float first = -(oneDegree * 10.0);
float second = (oneDegree * 10.0);
float step = 0.000001;
float[] r = iota(first,second,step).array;

writeln(r);

float item = 0.174531;
writeln(r.canFind(item));


// returns false for canFind - even though that float is in the array ???
February 26, 2015
On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
> float oneDegree = (PI / 180.0);
> float first = -(oneDegree * 10.0);
> float second = (oneDegree * 10.0);
> float step = 0.000001;
> float[] r = iota(first,second,step).array;
>
> writeln(r);
>
> float item = 0.174531;
> writeln(r.canFind(item));
>
>
> // returns false for canFind - even though that float is in the array ???

Never check floating point numbers for equality, unless you've really thought about how the floating point arithmetic for this specific problem will go. Pretty much the only place it's useful to do is in unit tests for maths libraries.
February 26, 2015
On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
> float oneDegree = (PI / 180.0);
> float first = -(oneDegree * 10.0);
> float second = (oneDegree * 10.0);
> float step = 0.000001;
> float[] r = iota(first,second,step).array;
>
> writeln(r);
>
> float item = 0.174531;
> writeln(r.canFind(item));
>
>
> // returns false for canFind - even though that float is in the array ???

also mark your float litteral with the f postfix. By default FP litterals are double...IIRC

float oneDegree = (PI / 180.0f);
float first = -(oneDegree * 10.0f);
float second = (oneDegree * 10.0f);
float step = 0.000001f;
float[] r = iota(first,second,step).array;

writeln(r);

float item = 0.174531f;
writeln(r.canFind(item));
February 26, 2015
On Thursday, 26 February 2015 at 11:04:58 UTC, Baz wrote:
> On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
>> float oneDegree = (PI / 180.0);
>> float first = -(oneDegree * 10.0);
>> float second = (oneDegree * 10.0);
>> float step = 0.000001;
>> float[] r = iota(first,second,step).array;
>>
>> writeln(r);
>>
>> float item = 0.174531;
>> writeln(r.canFind(item));
>>
>>
>> // returns false for canFind - even though that float is in the array ???
>
> also mark your float litteral with the f postfix. By default FP litterals are double...IIRC
>
> float oneDegree = (PI / 180.0f);
> float first = -(oneDegree * 10.0f);
> float second = (oneDegree * 10.0f);
> float step = 0.000001f;
> float[] r = iota(first,second,step).array;
>
> writeln(r);
>
> float item = 0.174531f;
> writeln(r.canFind(item));

Adding the f still produces a false result. Also I tried changing all to double but still not working - I always get false back. Interestingly if I harcode the output of the iota into an array - then things start to work as I expect.
February 26, 2015
On Thursday, 26 February 2015 at 11:12:42 UTC, Kingsley wrote:
> On Thursday, 26 February 2015 at 11:04:58 UTC, Baz wrote:
>> On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
>>> float oneDegree = (PI / 180.0);
>>> float first = -(oneDegree * 10.0);
>>> float second = (oneDegree * 10.0);
>>> float step = 0.000001;
>>> float[] r = iota(first,second,step).array;
>>>
>>> writeln(r);
>>>
>>> float item = 0.174531;
>>> writeln(r.canFind(item));
>>>
>>>
>>> // returns false for canFind - even though that float is in the array ???
>>
>> also mark your float litteral with the f postfix. By default FP litterals are double...IIRC
>>
>> float oneDegree = (PI / 180.0f);
>> float first = -(oneDegree * 10.0f);
>> float second = (oneDegree * 10.0f);
>> float step = 0.000001f;


Hardcoding the double[] does work as expected - so why doesn't it work with the iota generated array?

double oneDegree = (PI / 180.0);
double first = -(oneDegree * 10.0);
double second = (oneDegree * 10.0);
double step = 0.000001;
double[] r = iota(first,second,step).array;

writeln(r);

double[] hardCoded = [ 0.174521, 0.174522, 0.174523, 0.174524, 0.174525, 0.174526, 0.174527, 0.174528, 0.174529, 0.17453, 0.174531, 0.174532];

double item = 0.174531;
writeln(r.canFind(item));  // false - I expect true!!!!

writeln(hardCoded.canFind(item)); // true - as I expect
>> float[] r = iota(first,second,step).array;
>>
>> writeln(r);
>>
>> float item = 0.174531f;
>> writeln(r.canFind(item));
>
> Adding the f still produces a false result. Also I tried changing all to double but still not working - I always get false back. Interestingly if I harcode the output of the iota into an array - then things start to work as I expect.

February 26, 2015
On Thursday, 26 February 2015 at 11:12:42 UTC, Kingsley wrote:
> On Thursday, 26 February 2015 at 11:04:58 UTC, Baz wrote:
>> On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
>>> float oneDegree = (PI / 180.0);
>>> float first = -(oneDegree * 10.0);
>>> float second = (oneDegree * 10.0);
>>> float step = 0.000001;
>>> float[] r = iota(first,second,step).array;
>>>
>>> writeln(r);
>>>
>>> float item = 0.174531;
>>> writeln(r.canFind(item));
>>>
>>>
>>> // returns false for canFind - even though that float is in the array ???
>>
>> also mark your float litteral with the f postfix. By default FP litterals are double...IIRC
>>
>> float oneDegree = (PI / 180.0f);
>> float first = -(oneDegree * 10.0f);
>> float second = (oneDegree * 10.0f);
>> float step = 0.000001f;
>> float[] r = iota(first,second,step).array;
>>
>> writeln(r);
>>
>> float item = 0.174531f;
>> writeln(r.canFind(item));
>
> Adding the f still produces a false result. Also I tried changing all to double but still not working - I always get false back. Interestingly if I harcode the output of the iota into an array - then things start to work as I expect.

Sorry, in the past i've found that similar questions about FP can
be solved by following this way. There must be something that is
not 'float' in the processing...
February 26, 2015
On Thursday, 26 February 2015 at 11:17:12 UTC, Kingsley wrote:
> Hardcoding the double[] does work as expected - so why doesn't it work with the iota generated array?

'double' represents a floating-point type with base 2.

This implies that decimal numbers like 0.1 (= 1/10 = 1/(2*5)) cannot be exactly represented using double. The double literal 0.1 refers to a number close to but not equal to the real number 0.1.

So when you use a literal step of 0.1 you actually use step 1.00000000000000005551115123126E-1.

The small error adds up in successive additions and, due to a finite number of digits, every addition can introduce further error.
February 26, 2015
On Thursday, 26 February 2015 at 11:00:05 UTC, John Colvin wrote:
> On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
>> float oneDegree = (PI / 180.0);
>> float first = -(oneDegree * 10.0);
>> float second = (oneDegree * 10.0);
>> float step = 0.000001;
>> float[] r = iota(first,second,step).array;
>>
>> writeln(r);
>>
>> float item = 0.174531;
>> writeln(r.canFind(item));
>>
>>
>> // returns false for canFind - even though that float is in the array ???
>
> Never check floating point numbers for equality, unless you've really thought about how the floating point arithmetic for this specific problem will go. Pretty much the only place it's useful to do is in unit tests for maths libraries.

This is the classic reference on the topic: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

but there are loads of other less rigorous explanations around the web.

To cut a long story short: floating point maths is not the same as maths with real numbers. It's mostly roughly the same, sometimes catastrophically different and very, very rarely exactly the same.
February 26, 2015
Hi John.

Tks help with ldc - will look at that shortly.

So Kingsly needs to use a predicate for canFind that returns true if the two values being compared are close enough to being the same given floating point quirks ?

Ie I think people diagnosed the problem, but what is the solution...

On Thursday, 26 February 2015 at 11:00:05 UTC, John Colvin wrote:
> On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote:
>> float oneDegree = (PI / 180.0);
>> float first = -(oneDegree * 10.0);
>> float second = (oneDegree * 10.0);
>> float step = 0.000001;
>> float[] r = iota(first,second,step).array;
>>
>> writeln(r);
>>
>> float item = 0.174531;
>> writeln(r.canFind(item));
>>
>>
>> // returns false for canFind - even though that float is in the array ???
>
> Never check floating point numbers for equality, unless you've really thought about how the floating point arithmetic for this specific problem will go. Pretty much the only place it's useful to do is in unit tests for maths libraries.

February 26, 2015
Laeeth Isharc:

> Ie I think people diagnosed the problem, but what is the solution...

A possible solution:


void main() @safe {
    import std.stdio, std.range, std.algorithm, std.math;

    immutable float oneDegree = (PI / 180.0f);
    immutable float first = -(oneDegree * 10.0f);
    immutable float second = (oneDegree * 10.0f);
    immutable float step = 0.000001f;
    immutable float[] r = iota(first, second, step).array;

    //r.writeln;

    immutable float item = 0.174531f;
    r.canFind!q{ feqrel(cast()a, cast()b) >= 21 }(item).writeln;
}


Bye,
bearophile
« First   ‹ Prev
1 2