www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - double.init is nan ..?

reply Etienne <etcimon gmail.com> writes:
I'm trying to compare two doubles as part of a cache framework. To put 
it simply, double.init == double.init ... is false?

I don't understand. Maybe this belongs is D.learn, but I have no idea 
why or how this could possibly be normal behavior.

Does anyone have a clue? Thanks!
Mar 14 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Etienne:

 I'm trying to compare two doubles as part of a cache framework. 
 To put it simply, double.init == double.init ... is false?

 I don't understand. Maybe this belongs is D.learn, but I have 
 no idea why or how this could possibly be normal behavior.

 Does anyone have a clue? Thanks!

Yes, it's a question for D.learn. And double.init is a NaN. NaN comparisons return false. Bye, bearophile
Mar 14 2014
parent reply Etienne <etcimon gmail.com> writes:
On 2014-03-14 12:10 PM, Adam D. Ruppe wrote:
 On Friday, 14 March 2014 at 16:06:17 UTC, bearophile wrote:
 And double.init is a NaN.

Yes, and the reason for this is NaN is similar to null - an invalid state, so it can help you to catch uninitialized variables. You should explicitly initialize the variables normally and for the cache case, either keep a separate variable to tell if it is initialized (since NaN might be a valid cache state, like how an int may legitimately be 0) or compare using std.math.isNaN.

The cache library stores serialized strings mostly, and returns an empty value if there's a get on an empty key (like redis), so I was surprised to see get("key").unpack!double == double.init == false even when they key doesn't exist. So, I guess I'll have to modify msgpack-d to give doubles a 0.000 initialization value!
Mar 14 2014
parent reply Etienne <etcimon gmail.com> writes:
On 2014-03-14 12:14 PM, Etienne wrote:
 On 2014-03-14 12:10 PM, Adam D. Ruppe wrote:
 On Friday, 14 March 2014 at 16:06:17 UTC, bearophile wrote:
 And double.init is a NaN.

Yes, and the reason for this is NaN is similar to null - an invalid state, so it can help you to catch uninitialized variables. You should explicitly initialize the variables normally and for the cache case, either keep a separate variable to tell if it is initialized (since NaN might be a valid cache state, like how an int may legitimately be 0) or compare using std.math.isNaN.


Ok isNaN works on the deserialized values and simple comparisons works on the serialized values in the cache store. Struct.init is unreliable now in my books. Thanks!
Mar 14 2014
parent Etienne <etcimon gmail.com> writes:
On 2014-03-14 1:01 PM, Adam D. Ruppe wrote:
 On Friday, 14 March 2014 at 16:50:11 UTC, bearophile wrote:
 Keep in mind that there are many NaNs, and double.nan is not the same
 as dounle init.

Oh yeah, I forgot about that! (double.init is a signaling nan while double.nan is not. There's a whole bunch of other nans possible in floating point too btw) You're right. Looks like "is" always just compares the raw bits, which is good stuff when comparing with init.
 So this passes:

 assert(test is double.init);


OK so I don't have to pack the structs to compare them! Thanks :)
Mar 14 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 14 March 2014 at 16:06:17 UTC, bearophile wrote:
 And double.init is a NaN.

Yes, and the reason for this is NaN is similar to null - an invalid state, so it can help you to catch uninitialized variables. You should explicitly initialize the variables normally and for the cache case, either keep a separate variable to tell if it is initialized (since NaN might be a valid cache state, like how an int may legitimately be 0) or compare using std.math.isNaN.
Mar 14 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 14 March 2014 at 16:25:59 UTC, Etienne wrote:
 Struct.init is unreliable now in my books. Thanks!

Interestingly: struct A{ int a; double b; } void main() { A a; assert(a is A.init); // passes assert(a == A.init); // fails double test; assert(test is double.nan); // fails } I struct == other_struct works basically by checking the equality operator on each member inside. So that is like saying assert(a.a == A.init.a && b.a ==B.init.b) which fails cuz of the nan rule. Whereas struct is other_struct works by just comparing the memory bytes, regardless of the types of the contents. If they match, it is considered a pass, which will always be the case for comparing against init.
Mar 14 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

         double test;
         assert(test is double.nan); // fails

Keep in mind that there are many NaNs, and double.nan is not the same as dounle init. So this passes: assert(test is double.init); Bye, bearophile
Mar 14 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 14 March 2014 at 16:50:11 UTC, bearophile wrote:
 Keep in mind that there are many NaNs, and double.nan is not 
 the same as dounle init.

Oh yeah, I forgot about that! (double.init is a signaling nan while double.nan is not. There's a whole bunch of other nans possible in floating point too btw) You're right. Looks like "is" always just compares the raw bits, which is good stuff when comparing with init.
 So this passes:

 assert(test is double.init);

Mar 14 2014
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Etienne:

 OK so I don't have to pack the structs to compare them! Thanks 
 :)

"is" between complex values should be seen as a special tool, to be used carefully. It's not a good idea to use it widely and carelessly. Bye, bearophie
Mar 14 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Friday, 14 March 2014 at 17:54:23 UTC, bearophile wrote:
 "is" between complex values should be seen as a special tool, 
 to be used carefully. It's not a good idea to use it widely and 
 carelessly.

Perhaps, but when comparing between the init value it should always work because they do the same thing: init is the bytes copied to the type when it is first declared is compares the two sets of bytes Since both are about a simple byte block it should be pretty well reliable.
Mar 14 2014
prev sibling parent luka8088 <luka8088 owave.net> writes:
On 14.3.2014. 17:04, Etienne wrote:
 I'm trying to compare two doubles as part of a cache framework. To put
 it simply, double.init == double.init ... is false?

Note that you should not compare floating point types for equality! http://www.parashift.com/c++-faq/floating-point-arith.html
Mar 15 2014