Thread overview
double.init is real.nan, is it a bug?
Aug 15, 2013
bsd
Aug 15, 2013
JS
Aug 15, 2013
Jonathan M Davis
Aug 15, 2013
bsd
Aug 15, 2013
Jonathan M Davis
August 15, 2013
Hi all,


I think this is a bug, but if not I'm very confused and would like some clarification.

When checking double values that could be nan or unassigned I have to check both double.init and double.nan. But double.init IS double.nan.

---
void main() {
    // passes but I believe it is checked during compile
    assert(double.init is double.nan);

    double val;
    std.stdio.writeln( to!string(val) ); // writes "nan" to console
    assert(val is double.init); // passes
    assert(val is double.nan); // << FAILS (unexpectedly for me anyway)
}
---

Why does assert(val is double.nan) fail? Given:

a) double.init is double.nan
b) val is double.init
c) to!string(val) sees val as a nan

I also found this confusing:
---
void main() {

    assert(double.init is double.nan); // passes expected

    assert(double.init is float.init); // passes, unexpected
    assert(double.init is real.init); // passes, unexpected

    assert(double.init is real.nan); // passes, unexpected
    assert(double.init is float.nan); // passes, unexpected

}
---
I don't think these should be passing...should they??

I'm on fedora 19, dmd 2.063.2 extracted from the ZIP

Thanks
August 15, 2013
On Thursday, 15 August 2013 at 04:01:28 UTC, bsd wrote:
> Hi all,
>
>
> I think this is a bug, but if not I'm very confused and would like some clarification.
>
> When checking double values that could be nan or unassigned I have to check both double.init and double.nan. But double.init IS double.nan.
>
> ---
> void main() {
>     // passes but I believe it is checked during compile
>     assert(double.init is double.nan);
>
>     double val;
>     std.stdio.writeln( to!string(val) ); // writes "nan" to console
>     assert(val is double.init); // passes
>     assert(val is double.nan); // << FAILS (unexpectedly for me anyway)
> }
> ---
>
> Why does assert(val is double.nan) fail? Given:
>
> a) double.init is double.nan
> b) val is double.init
> c) to!string(val) sees val as a nan
>
> I also found this confusing:
> ---
> void main() {
>
>     assert(double.init is double.nan); // passes expected
>
>     assert(double.init is float.init); // passes, unexpected
>     assert(double.init is real.init); // passes, unexpected
>
>     assert(double.init is real.nan); // passes, unexpected
>     assert(double.init is float.nan); // passes, unexpected
>
> }
> ---
> I don't think these should be passing...should they??
>
> I'm on fedora 19, dmd 2.063.2 extracted from the ZIP
>
> Thanks

There is the issue with order on is. Try reversing them and see if you get the same results. I imagine for floats and doubles are interchangeable for nans(both are nan, regardless of the encoding used).
August 15, 2013
On Thursday, August 15, 2013 06:01:21 bsd wrote:
> Hi all,
> 
> 
> I think this is a bug, but if not I'm very confused and would like some clarification.
> 
> When checking double values that could be nan or unassigned I have to check both double.init and double.nan. But double.init IS double.nan.
> 
> ---
> void main() {
>      // passes but I believe it is checked during compile
>      assert(double.init is double.nan);
> 
>      double val;
>      std.stdio.writeln( to!string(val) ); // writes "nan" to
> console
>      assert(val is double.init); // passes
>      assert(val is double.nan); // << FAILS (unexpectedly for me
> anyway)
> }
> ---
> 
> Why does assert(val is double.nan) fail? Given:
> 
> a) double.init is double.nan
> b) val is double.init
> c) to!string(val) sees val as a nan

There are multiple values for NaN. It's still a bit surprising to me that assert(val is double.nan) failed, but as long as val is still one of the values for NaN, it shouldn't matter. It wouldn't have been at all suprising though if you had two different NaNs which were generated through arithmetic which didn't match. In general, you can't rely on the bit pattern for NaN.

> I also found this confusing:
> ---
> void main() {
> 
>      assert(double.init is double.nan); // passes expected
> 
>      assert(double.init is float.init); // passes, unexpected
>      assert(double.init is real.init); // passes, unexpected
> 
>      assert(double.init is real.nan); // passes, unexpected
>      assert(double.init is float.nan); // passes, unexpected
> 
> }
> ---
> I don't think these should be passing...should they??

To do the comparison, the same size types must be compared, so the smaller floating point types are promoted to the larger type in the expression, and evidently, promoting the init value of a smaller floating point value gives you the same value as the init value of the larger floating point value.

- Jonathan M Davis
August 15, 2013
On Thursday, 15 August 2013 at 05:12:35 UTC, Jonathan M Davis wrote:
> On Thursday, August 15, 2013 06:01:21 bsd wrote:
>> Hi all,
>> 
>
> There are multiple values for NaN. It's still a bit surprising to me that
> assert(val is double.nan) failed, but as long as val is still one of the
> values for NaN, it shouldn't matter. It wouldn't have been at all suprising
> though if you had two different NaNs which were generated through arithmetic
> which didn't match. In general, you can't rely on the bit pattern for NaN.
>
>> I also found this confusing:
>> ---
>> void main() {
>> 
>>      assert(double.init is double.nan); // passes expected
>> 
>>      assert(double.init is float.init); // passes, unexpected
>>      assert(double.init is real.init); // passes, unexpected
>> 
>>      assert(double.init is real.nan); // passes, unexpected
>>      assert(double.init is float.nan); // passes, unexpected
>> 
>> }
>> ---
>> I don't think these should be passing...should they??
>
> To do the comparison, the same size types must be compared, so the smaller
> floating point types are promoted to the larger type in the expression, and
> evidently, promoting the init value of a smaller floating point value gives you
> the same value as the init value of the larger floating point value.
>
> - Jonathan M Davis

This explains why (double.nan is float.nan) && (double.nan is real.nan). I understand that now, thanks.

I found std.math.isNaN in just after I posted, I really should read the docs first :D

For some reason I thought ('var' is double.nan) did this isNaN check, sort of like (key in AA) ... but 'in' is in and 'is' is, well, just is.

Thanks for the help.

August 15, 2013
On Thursday, August 15, 2013 08:20:01 bsd wrote:
> For some reason I thought ('var' is double.nan) did this isNaN
> check, sort of like (key in AA) ... but 'in' is in and 'is' is,
> well, just is.

The is operate does a bitwise comparison, so it's checking whether the bits are identical or not. The primary place that it's used is comparing pointers. Beyond that, its use should probably be fairly rare as in most cases, what you want is ==.

- Jonathan M Davis