2

How can I specify a specific double precision literal or value in c#?

For example, I would like to use the constant of the largest double value less than one in a program. The largest double less than one is 1.11111111 11111111 11111111 11111111 11111111 11111111 1111 x 2^(-1) in binary. Expressing this as a big-endian double in hex would be 0x3fe f ffff ffff ffff

I can generate it with the following code:

var largestDoubleLessThanOneBytes = new byte[] {0x3f, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (BitConverter.IsLittleEndian) largestDoubleLessThanOneBytes = largestDoubleLessThanOneBytes.Reverse().ToArray();
double largestDoubleLessThanOne = BitConverter.ToDouble(largestDoubleLessThanOneBytes, 0);

BitConverter can't be used in the declaration of a const, so this can't be used in place of a literal value.

Using this tool, I can come up with the literal 9.99999999999999888977697537484E-1, which ends up being exactly the same double. BitConverter.ToString(BitConverter.GetBytes(9.99999999999999888977697537484E-1)) == "FF-FF-FF-FF-FF-FF-EF-3F".

Is there any other way to get specific double values into c# code than to find a decimal literal whose closest double representation is the double you want?

Cirdec
  • 24,019
  • 2
  • 50
  • 100
  • You can also get c# code to spit out an appropriate decimal literal for a double with `.ToString("R")`. In this case it would be `0.99999999999999989`. Attempting to add enough decimal places to a string format to output a value precise enough to use as a literal doesn't work, for why see http://stackoverflow.com/questions/1421520/formatting-doubles-for-output-in-c-sharp – Cirdec Jun 25 '14 at 23:30
  • In Java, I would use Math.nextAfter(1.0, Double.NEGATIVE_INFINITY). Is this perhaps a case for a C# nextAfter function? – Patricia Shanahan Jun 26 '14 at 08:04

1 Answers1

2

This is probably overkill, but damn, why not?

unsafe
{
    var x = 0x3fefffffffffffff;
    var d = *(double*)&x;
    Console.WriteLine("{0:r}", d);
}

hello, reinterpret_cast<> in C#

Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • 1
    Unfortunately, the .Net 4.5 C# compiler isn't clever enough to optimize away `*&`, much less `*(double*)&`. It results in a `ldc.i8`, `stloc`, `lsloca.s`, `conf.u`, `ldind.r8`, `stloc` and uses two locals instead of simply `ldc.r8`, `stloc` using a single local. – Cirdec Jun 26 '14 at 16:49
  • The real optimizations in .Net code are made during the JIT compilation. I don't know how smart the JITter is, but it may play a significant role here. Anyway, since you want to specify a compile-time constant it shouldn't matter much. – Lucas Trzesniewski Jun 26 '14 at 21:11