View mode: basic / threaded / horizontal-split · Log in · Help
August 25, 2010
Three floating point questions
This program prints (dmd 2.048):
7ff4000000000000
7ffc000000000000

// program #1
import std.stdio: writeln, writefln;
import std.string: format;
void main() {
   string toHex(T)(T x) {
       string result;
       ubyte* ptr = cast(ubyte*)&x;
       foreach (i; 0 .. T.sizeof)
           result = format("%02x", ptr[i]) ~ result;
       return result;
   }
   writeln(toHex(double.init));
   writefln("%x", cast(ulong)double.init);
}

Do you know what cast(ulong) is doing here?

---------------------------

This program prints (dmd 2.048)::
-nan

// program #2
import std.stdio: writeln;
void main() {
   writeln(0.0 / 0.0);
}

Is it a bug of writeln?

---------------------------

Do you know why this isn't raising runtime errors?

// program #3
import std.math: FloatingPointControl;
import std.c.stdlib: atof;
void main() {
   double d3 = atof("3.0");
   double x; // nan
   FloatingPointControl fpc;
   fpc.enableExceptions(FloatingPointControl.severeExceptions);
   double r = x * d3;
}

Bye,
bearophile
August 26, 2010
Re: Three floating point questions
bearophile wrote:
> This program prints (dmd 2.048):
> 7ff4000000000000
> 7ffc000000000000
> 
> // program #1
> import std.stdio: writeln, writefln;
> import std.string: format;
> void main() {
>     string toHex(T)(T x) {
>         string result;
>         ubyte* ptr = cast(ubyte*)&x;
>         foreach (i; 0 .. T.sizeof)
>             result = format("%02x", ptr[i]) ~ result;
>         return result;
>     }
>     writeln(toHex(double.init));
>     writefln("%x", cast(ulong)double.init);
> }
> 
> Do you know what cast(ulong) is doing here?

Turning it from a signalling nan to a quiet nan.

> ---------------------------
> 
> This program prints (dmd 2.048)::
> -nan
> 
> // program #2
> import std.stdio: writeln;
> void main() {
>     writeln(0.0 / 0.0);
> }
> 
> Is it a bug of writeln?

You mean, because it's a negative nan?

> ---------------------------
> 
> Do you know why this isn't raising runtime errors?
> 
> // program #3
> import std.math: FloatingPointControl;
> import std.c.stdlib: atof;
> void main() {
>     double d3 = atof("3.0");
>     double x; // nan
>     FloatingPointControl fpc;
>     fpc.enableExceptions(FloatingPointControl.severeExceptions);
>     double r = x * d3;
> }

That's a known bug in the backend, which I still haven't fixed. The 
signalling nans get triggered in the 'double x; ' line.
This happens because there's a difference in the way AMD and Intel deal 
with signalling nans, which is completely unpublicised. So my initial 
testing was inadequate.
August 26, 2010
Re: Three floating point questions
Don:
> > Do you know what cast(ulong) is doing here?
> 
> Turning it from a signalling nan to a quiet nan.

I really really didn't know this. Is this written somewhere in the D docs? :-)


> You mean, because it's a negative nan?

Yes, I mean that. Is a negative nan a meaningful concept? Is it a true negative nan coming from the division of two positive values, or it's just a bug of writeln, or is it something completely different?


> The signalling nans get triggered in the 'double x; ' line.

(You are often two steps forward compared to my thought patterns, so please be patient with me)
In this program the FP register is modified after that definition line, so I don't expect 'double x; ' to trigger an hardware exception.
But the 'double r = x * d3;' line computes the product of a signaling nan and a normal double, so this is an operation that has to produce an error, I think.


> This happens because there's a difference in the way AMD and Intel deal 
> with signalling nans, which is completely unpublicised. So my initial 
> testing was inadequate.

I see. If not even official CPU specs show such data, then not being right in the first (and second) implementation is forgiveable, I presume :o)

Bye and thank you,
bearophile
August 26, 2010
Re: Three floating point questions
bearophile wrote:
> Don:
>>> Do you know what cast(ulong) is doing here?
>> Turning it from a signalling nan to a quiet nan.
> 
> I really really didn't know this. Is this written somewhere in the D docs? :-)

It's the way signalling nans work. _Any_ use of them raises a floating 
point exception, then turns them into a quiet NaN.

>> You mean, because it's a negative nan?
> 
> Yes, I mean that. Is a negative nan a meaningful concept? 

It's part of the payload of the nan.

Is it a true negative nan coming from the division of two positive 
values, or it's just a bug of writeln, or is it something completely 
different?
> 
> 
>> The signalling nans get triggered in the 'double x; ' line.
> 
> (You are often two steps forward compared to my thought patterns, so please be patient with me)
> In this program the FP register is modified after that definition line, so I don't expect 'double x; ' to trigger an hardware exception.

Unfortunately the way the backend deals with it at present is to do:
double x;
x = double.init;
which is wrong because it involves an assignment, which may or may not 
trigger a floating point exception, depending on your cpu*.
If it triggers one, then x contains a quiet nan, instead of a signalling 
one! So the signalling nan idea doesn't quite work yet.

* it actually is documented in Intel/AMD docs for the FLD and FSTP 
instructions, but you have to read it _very_ carefully to notice. As far 
as I can tell, nobody has noticed the difference before. I only 
discovered it through experiment.
Top | Discussion index | About this forum | D home