digitalmars.D - Disallow (dis)equality with FP.nan/FP.init literals
- bearophile (98/98) Apr 18 2012 This is an open enhancement request that I'll probably add to
- so (12/110) Apr 18 2012 Good idea.
- so (3/144) Apr 18 2012 s/double/float/
- Maxim (4/15) Apr 19 2012 Gcc has warning option for comparing floats or doubles. I think
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/13) Apr 19 2012 +1. This enhancement will be helpful.
- Somedude (3/20) Apr 19 2012 Looks like a good one !
This is an open enhancement request that I'll probably add to Bugzilla. The direct cause of it is a recent discussion in D.learn, but I and other people are aware of this problem for a lot of time. Since a lot of time D statically refuses the use of "classReference == null": class Foo {} void main() { Foo f; assert(f == null); assert(f != null); } test.d(4): Error: use 'is' instead of '==' when comparing with null test.d(5): Error: use '!is' instead of '!=' when comparing with null A not expert D programmer sometimes compares a double with double.nan in a wrong way: http://forum.dlang.org/thread/mailman.1845.1334694574.4860.digitalmars-d-learn puremagic.com#post-jmlhfr:2428cv:241:40digitalmars.com because someDouble == double.nan is always false: import std.math: isNaN; void main() { double x = double.init; assert(x != double.nan); assert(x != double.init); assert(isNaN(x)); assert(x is double.init); assert(x !is double.nan); double y = double.nan; assert(y != double.nan); assert(y != double.init); assert(isNaN(y)); assert(y !is double.init); assert(y is double.nan); } I think there are three common wrong usage patterns of NaNs testing: 1) Test that x is equal to/different from nan using x==FP.nan/x!=FP.nan 2) Test that x is equal to/different from all NaNs using x==FP.nan/x!=FP.nan 3) Test that x is equal to/different from FP.init using x==FP.init/x!=FP.init The case 3 is a bit less important because the programmer already knows something about FP init, but it's wrong still. There are other wrong usages of NaNs but they are by more expert programmers, to I don't want to catch them (example: using "is" to test if x is equal to/different from all NaNs is a bug, because there are more than one NaN. But if the programmer uses "is" I assume he/she/shi knows enough about NaNs, so this is not flagged by the compiler). Currently this program compiles with no errors: void main() { float x1 = float.nan; assert(x1 == float.nan); float x2 = 0.0; assert(x2 != float.nan); float x3 = float.init; assert(x3 == float.init); float x4 = 0.0; assert(x4 != float.init); double x5 = double.nan; assert(x5 == double.nan); double x6 = 0.0; assert(x6 != double.nan); double x7 = double.init; assert(x7 == double.init); double x8 = 0.0; assert(x8 != double.init); real x9 = real.nan; assert(x9 == real.nan); real x10 = 0.0; assert(x10 != real.nan); real x11 = real.init; assert(x11 == real.init); real x12 = 0.0; assert(x12 != real.init); enum double myNaN = double.nan; assert(myNaN == double.nan); } it generates errors similar to: test.d(4): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.nan' for this specific NaN test.d(6): Error: comparison is always true. Use '!std.math.isNaN' to test for every kind of NaN or '!is float.nan' for this specific NaN test.d(8): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.init' for this specicif NaN ... Opinions, improvements, votes or critics are welcome. Bye, bearophile
Apr 18 2012
On Thursday, 19 April 2012 at 00:50:09 UTC, bearophile wrote:This is an open enhancement request that I'll probably add to Bugzilla. The direct cause of it is a recent discussion in D.learn, but I and other people are aware of this problem for a lot of time. Since a lot of time D statically refuses the use of "classReference == null": class Foo {} void main() { Foo f; assert(f == null); assert(f != null); } test.d(4): Error: use 'is' instead of '==' when comparing with null test.d(5): Error: use '!is' instead of '!=' when comparing with null A not expert D programmer sometimes compares a double with double.nan in a wrong way: http://forum.dlang.org/thread/mailman.1845.1334694574.4860.digitalmars-d-learn puremagic.com#post-jmlhfr:2428cv:241:40digitalmars.com because someDouble == double.nan is always false: import std.math: isNaN; void main() { double x = double.init; assert(x != double.nan); assert(x != double.init); assert(isNaN(x)); assert(x is double.init); assert(x !is double.nan); double y = double.nan; assert(y != double.nan); assert(y != double.init); assert(isNaN(y)); assert(y !is double.init); assert(y is double.nan); } I think there are three common wrong usage patterns of NaNs testing: 1) Test that x is equal to/different from nan using x==FP.nan/x!=FP.nan 2) Test that x is equal to/different from all NaNs using x==FP.nan/x!=FP.nan 3) Test that x is equal to/different from FP.init using x==FP.init/x!=FP.init The case 3 is a bit less important because the programmer already knows something about FP init, but it's wrong still. There are other wrong usages of NaNs but they are by more expert programmers, to I don't want to catch them (example: using "is" to test if x is equal to/different from all NaNs is a bug, because there are more than one NaN. But if the programmer uses "is" I assume he/she/shi knows enough about NaNs, so this is not flagged by the compiler). Currently this program compiles with no errors: void main() { float x1 = float.nan; assert(x1 == float.nan); float x2 = 0.0; assert(x2 != float.nan); float x3 = float.init; assert(x3 == float.init); float x4 = 0.0; assert(x4 != float.init); double x5 = double.nan; assert(x5 == double.nan); double x6 = 0.0; assert(x6 != double.nan); double x7 = double.init; assert(x7 == double.init); double x8 = 0.0; assert(x8 != double.init); real x9 = real.nan; assert(x9 == real.nan); real x10 = 0.0; assert(x10 != real.nan); real x11 = real.init; assert(x11 == real.init); real x12 = 0.0; assert(x12 != real.init); enum double myNaN = double.nan; assert(myNaN == double.nan); } so it generates errors similar to: test.d(4): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.nan' for this specific NaN test.d(6): Error: comparison is always true. Use '!std.math.isNaN' to test for every kind of NaN or '!is float.nan' for this specific NaN test.d(8): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.init' for this specicif NaN ... Opinions, improvements, votes or critics are welcome. Bye, bearophileGood idea. But nothing beats this: int main() { double q; q = 3.0/7.0; if (q == 3.0/7.0) printf("Equal\n"); else printf("Not Equal\n"); return 0; } http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html Should we disable implicit conversion "at" comparison as well?
Apr 18 2012
On Thursday, 19 April 2012 at 01:28:51 UTC, so wrote:On Thursday, 19 April 2012 at 00:50:09 UTC, bearophile wrote:s/double/float/ "double" version also problematic but for another case.This is an open enhancement request that I'll probably add to Bugzilla. The direct cause of it is a recent discussion in D.learn, but I and other people are aware of this problem for a lot of time. Since a lot of time D statically refuses the use of "classReference == null": class Foo {} void main() { Foo f; assert(f == null); assert(f != null); } test.d(4): Error: use 'is' instead of '==' when comparing with null test.d(5): Error: use '!is' instead of '!=' when comparing with null A not expert D programmer sometimes compares a double with double.nan in a wrong way: http://forum.dlang.org/thread/mailman.1845.1334694574.4860.digitalmars-d-learn puremagic.com#post-jmlhfr:2428cv:241:40digitalmars.com because someDouble == double.nan is always false: import std.math: isNaN; void main() { double x = double.init; assert(x != double.nan); assert(x != double.init); assert(isNaN(x)); assert(x is double.init); assert(x !is double.nan); double y = double.nan; assert(y != double.nan); assert(y != double.init); assert(isNaN(y)); assert(y !is double.init); assert(y is double.nan); } I think there are three common wrong usage patterns of NaNs testing: 1) Test that x is equal to/different from nan using x==FP.nan/x!=FP.nan 2) Test that x is equal to/different from all NaNs using x==FP.nan/x!=FP.nan 3) Test that x is equal to/different from FP.init using x==FP.init/x!=FP.init The case 3 is a bit less important because the programmer already knows something about FP init, but it's wrong still. There are other wrong usages of NaNs but they are by more expert programmers, to I don't want to catch them (example: using "is" to test if x is equal to/different from all NaNs is a bug, because there are more than one NaN. But if the programmer uses "is" I assume he/she/shi knows enough about NaNs, so this is not flagged by the compiler). Currently this program compiles with no errors: void main() { float x1 = float.nan; assert(x1 == float.nan); float x2 = 0.0; assert(x2 != float.nan); float x3 = float.init; assert(x3 == float.init); float x4 = 0.0; assert(x4 != float.init); double x5 = double.nan; assert(x5 == double.nan); double x6 = 0.0; assert(x6 != double.nan); double x7 = double.init; assert(x7 == double.init); double x8 = 0.0; assert(x8 != double.init); real x9 = real.nan; assert(x9 == real.nan); real x10 = 0.0; assert(x10 != real.nan); real x11 = real.init; assert(x11 == real.init); real x12 = 0.0; assert(x12 != real.init); enum double myNaN = double.nan; assert(myNaN == double.nan); } so it generates errors similar to: test.d(4): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.nan' for this specific NaN test.d(6): Error: comparison is always true. Use '!std.math.isNaN' to test for every kind of NaN or '!is float.nan' for this specific NaN test.d(8): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.init' for this specicif NaN ... Opinions, improvements, votes or critics are welcome. Bye, bearophileGood idea. But nothing beats this: int main() { double q; q = 3.0/7.0; if (q == 3.0/7.0) printf("Equal\n"); else printf("Not Equal\n"); return 0; } http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html Should we disable implicit conversion "at" comparison as well?
Apr 18 2012
On Thursday, 19 April 2012 at 01:28:51 UTC, so wrote:Good idea. But nothing beats this: int main() { double q; q = 3.0/7.0; if (q == 3.0/7.0) printf("Equal\n"); else printf("Not Equal\n"); return 0; } http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html Should we disable implicit conversion "at" comparison as well?Gcc has warning option for comparing floats or doubles. I think it would be good idea to introduce warnings (or errors) in dmd too.
Apr 19 2012
On 04/18/2012 05:50 PM, bearophile wrote:This is an open enhancement request that I'll probably add to Bugzilla. The direct cause of it is a recent discussion in D.learn, but I and other people are aware of this problem for a lot of time.[...]assert(myNaN == double.nan); } generates errors similar to: test.d(4): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.nan' for this specific NaN+1. This enhancement will be helpful. Ali
Apr 19 2012
Le 19/04/2012 02:50, bearophile a écrit :This is an open enhancement request that I'll probably add to Bugzilla....generates errors similar to: test.d(4): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.nan' for this specific NaN test.d(6): Error: comparison is always true. Use '!std.math.isNaN' to test for every kind of NaN or '!is float.nan' for this specific NaN test.d(8): Error: comparison is always false. Use 'std.math.isNaN' to test for every kind of NaN or 'is float.init' for this specicif NaN ... Opinions, improvements, votes or critics are welcome. Bye, bearophileLooks like a good one !
Apr 19 2012