Search code examples
typescastingfloating-pointd

Untyped decimal literals


Using this code:

import std.conv, std.stdio;

void main() {
   auto s = "2.9";
   auto n = s.to!(float);
   auto n2 = s.to!(double);
   auto n3 = s.to!(real);
   [n == 2.9, n2 == 2.9, n3 == 2.9].writeln;
}

I get this result:

[false, false, false]

Huh? If a literal 2.9 is not a float, double or real, what is it?


Solution

  • At run.dlang.io, I'm seeing [false, true, true].

    This may give you a hint as to why you're getting the results you see:

    writefln("%a", n);
    writefln("%a", n2);
    writefln("%a", n3);
    writefln("%a", 2.9);
    

    Due to how floating point values are stored, you can't rely on == when you've done any sort of transformation on them. In this case, since the values are parsed from a string, you aren't seeing the precise bit pattern that matches the literal 2.9. Contrast that with the below code, which should result in an array of true values:

    auto n = 2.9;
    auto n2 = 2.9;
    auto n3 = 2.9;
    [n == 2.9, n2 == 2.9, n3 == 2.9].writeln;
    

    So in your case, you probably should use std.math.approxEqual:

    [approxEqual(n, 2.9), approxEqual(n2, 2.9), approxEqual(n3, 2.9)].writeln;
    

    I also recommend Don Clugston's DConf 2016 talk, Using Floating Point Without Losing Your Sanity.