digitalmars.D - What am I doing wrong here - canFind with iota is not working
- Kingsley (10/10) Feb 26 2015 float oneDegree = (PI / 180.0);
- John Colvin (5/15) Feb 26 2015 Never check floating point numbers for equality, unless you've
- John Colvin (9/28) Feb 26 2015 This is the classic reference on the topic:
- Laeeth Isharc (8/27) Feb 26 2015 Hi John.
- bearophile (15/17) Feb 26 2015 A possible solution:
- bearophile (4/7) Feb 27 2015 With a recent Phobos bug fix you can now write:
- John Colvin (5/12) Feb 26 2015 My preference would be to find a way to construct the program
- Laeeth Isharc (6/21) Feb 26 2015 Thanks.
- Baz (11/21) Feb 26 2015 also mark your float litteral with the f postfix. By default FP
- Kingsley (5/30) Feb 26 2015 Adding the f still produces a false result. Also I tried changing
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 ???
Feb 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.
Feb 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: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.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.
Feb 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.
Feb 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
Feb 26 2015
immutable float item = 0.174531f; r.canFind!q{ feqrel(cast()a, cast()b) >= 21 }(item).writeln; }With a recent Phobos bug fix you can now write: r.canFind!q{ feqrel(a, b) >= 21 }(item).writeln; Bye, bearophile
Feb 27 2015
On Thursday, 26 February 2015 at 12:39:20 UTC, Laeeth Isharc wrote: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...My preference would be to find a way to construct the program such that it isn't needed. Failing that, std.math has feqrl and approxEqual for this task.
Feb 26 2015
Thanks. Rough version for Wiki here: http://wiki.dlang.org/Floating_Point_Gotchas It could be tidier, but I am not able to do so at moment. Feel free to change. On Thursday, 26 February 2015 at 14:04:17 UTC, John Colvin wrote:On Thursday, 26 February 2015 at 12:39:20 UTC, Laeeth Isharc wrote: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...My preference would be to find a way to construct the program such that it isn't needed. Failing that, std.math has feqrl and approxEqual for this task.
Feb 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));
Feb 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: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.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));
Feb 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: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 expectOn 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.
Feb 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.
Feb 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: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...On Thursday, 26 February 2015 at 10:55:43 UTC, Kingsley wrote: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.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));
Feb 26 2015