views:

3832

answers:

2

Is there any straightforward way to get the mantissa and exponent from a double in c# (or .NET in general)?

I found this example using google, but I'm not sure how robust it would be. Could the binary representation for a double change in some future version of the framework, etc?

The other alternative I found was to use System.Decimal instead of double and use the Decimal.GetBits() method to extract them.

Any suggestions?

+1  A: 

the representation is a IEEE standard and (probably) shouldn't change.

http://msdn.microsoft.com/en-us/library/aa691146(VS.71).aspx

EDIT: The reason why decimal has a getBits and double does not is that decimal preserves significant digits. 3.0000m == 3.00m but the exponents/mantissas are actually different. I think floats/doubles are uniquely represented.

Jimmy
A double does not necessarily have to be 64-bits in C/C++. I've worked on several systems where it is 32-bits (i.e. the same as a float). Is C# different?
Judge Maygarden
yes, it is defined in the spec as 64 bits. that's a good point about the double (and long/int/long long ) fiasco in C/C++
Jimmy
+5  A: 

The binary format shouldn't change - it would certainly be a breaking change to existing specifications. It's defined to be in IEEE754 / IEC 60559:1989 format, as Jimmy said. (C# 3.0 language spec section 1.3; ECMA 335 section 8.2.2). The code in DoubleConverter should be fine and robust.

For the sake of future reference, the relevant bit of the code is:

    // Translate the double into sign, exponent and mantissa.
    long bits = BitConverter.DoubleToInt64Bits(d);
    // Note that the shift is sign-extended, hence the test against -1 not 1
    bool negative = (bits < 0);
    int exponent = (int) ((bits >> 52) & 0x7ffL);
    long mantissa = bits & 0xfffffffffffffL;

    // Subnormal numbers; exponent is effectively one higher,
    // but there's no extra normalisation bit in the mantissa
    if (exponent==0)
    {
        exponent++;
    }
    // Normal numbers; leave exponent as it is but add extra
    // bit to the front of the mantissa
    else
    {
        mantissa = mantissa | (1L<<52);
    }

    // Bias the exponent. It's actually biased by 1023, but we're
    // treating the mantissa as m.0 rather than 0.m, so we need
    // to subtract another 52 from it.
    exponent -= 1075;

    if (mantissa == 0) 
    {
        return "0";
    }

    /* Normalize */
    while((mantissa & 1) == 0) 
    {    /*  i.e., Mantissa is even */
        mantissa >>= 1;
        exponent++;
    }

The comments made sense to me at the time, but I'm sure I'd have to think for a while about them now. After the very first part you've got the "raw" exponent and mantissa - the rest of the code just helps to treat them in a simpler fashion.

Jon Skeet
If I understand the spec correctly, there are two forms of the format, a normalized version and an un-normalized version. the bulk of the code handles converting the unnormalized mantissa/exponent to normalized form
Jimmy
I don't get the "subtract another 52" part. What's going on there?
Jay R.
@Jay R: It's slightly hard to explain, to be honest - the comment does about as good a job as I can think of. I guess it's easiest to give an example, but I'm afraid my brain is frazzled at the moment :(
Jon Skeet
Now that I've thought more about it, I get the 1075. 1023 plus 52 shifts to bring the mantissa from a very large number * 2^exponent to a small number.
Jay R.