Why were uninitialized floating-point variables changed to quiet NaN's in v2.087?

FinalEvilution FinalEvilution at gmail.com
Wed Jul 1 18:22:05 UTC 2026


Thank you for making the GitHub issue.



On Wednesday, 1 July 2026 at 11:49:42 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
> ```d
> float f;
>
> assert(f is float.init);
> ```
>
> That will fail.
>
> A signally NaN is a different value from a Quiet NaN and is 
> expression is a bit wise compare.

>
> Errr that should be float.nan not float.init.

Nether `assert(f is float.init)` or `assert(f is float.nan)` fail 
as
```
float f;
float.init;
float.nan;
```
are all
2143289344
2143289344
2143289344
Pre v2.087 this was
2141192192
2141192192
2143289344
which meant you could catch this or more complex examples at 
runtime using fp exceptions.
```
// This will generate a hardware exception, if x is a
// default-initialized floating point variable:
float x; // Add `= 0` or even `= real.nan` to not throw the 
exception.
float y = x * 3.0;
```
Walter said in the pull request
> They should have the same bit patterns. We tried to make .init 
> a signalling nan, but this was a complete failure. .init and 
> .nan should both be a quiet nan.

> Because a signalling nan converts to a quiet nan when used. The 
> problem was nobody could come up with a consistent definition 
> of "used".

Presumably this could cause problems if a signalling nan should 
thrown on an op, but then only being
thrown later or not at all, but with FloatingPointControl being 
scope local you'd still get help checking
for fp exceptions only where you'd want help checking for one.

I'm just not experienced enough with floating point programming 
to know what the problems would be.


More information about the Digitalmars-d-learn mailing list