Extracting mantissa and exponent from double in c#

29,170

Solution 1

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 in the example is:

public static string ToExactString (double d)
{
    …

    // 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 & (1L << 63)) != 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 negative ? "-0" : "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.

Solution 2

The representation is a IEEE standard and shouldn't change.

https://msdn.microsoft.com/en-us/library/system.double(v=vs.110).aspx

The Double type complies with the IEC 60559:1989 (IEEE 754) standard for binary floating-point arithmetic.

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.

Share:
29,170
dvenema
Author by

dvenema

Updated on April 13, 2021

Comments

  • dvenema
    dvenema about 3 years

    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?

  • Judge Maygarden
    Judge Maygarden over 15 years
    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?
  • Boti
    Boti over 15 years
    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++
  • Boti
    Boti over 15 years
    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
  • user507401
    user507401 over 13 years
    I don't get the "subtract another 52" part. What's going on there?
  • Jon Skeet
    Jon Skeet over 13 years
    @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 :(
  • user507401
    user507401 over 13 years
    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.
  • Slava
    Slava about 11 years
    @Jimmy when (or if) C# would support at least half platforms that C/C++ support then you can say something about fiasco in C/C++.
  • Daniel
    Daniel almost 11 years
    @JonSkeet Could you at some time check out my question here ( stackoverflow.com/questions/17829139/… )? I'm currently using part of this code and seem to be missing something.
  • Oleg Vazhnev
    Oleg Vazhnev over 10 years
    if someone can post similar code to convert decimal to mantissa and exponent? I guess Decimal.GetBits() method should be used.
  • Oleg Vazhnev
    Oleg Vazhnev over 10 years
    upd: I found here an example which calculates mantissa, but exponent is not calculated stackoverflow.com/a/764102/93647
  • Jon Skeet
    Jon Skeet over 10 years
    @javapowered: The code in this answer does calculate the exponent and mantissa. It's not clear what else you'd need.
  • Oleg Vazhnev
    Oleg Vazhnev over 10 years
    @JonSkeet right I was talking about another question stackoverflow.com/questions/763942/…. I asked in this question because when I posted my first comments I not found this, another, "decimal" question.
  • Slipp D. Thompson
    Slipp D. Thompson over 9 years
    Why is a single-character string with 0 text returned under a specific condition? I'm attempting to use your implementation in my project but am unsure of the larger context of this algorithm. I'm assuming a function with out args for mantissa and exponent, but that sole string return is throwing off my understanding.
  • Jon Skeet
    Jon Skeet over 9 years
    @SlippD.Thompson: If the mantissa isn't 0, there will be at least one non-zero digit. I suspect that if I removed that special case, it would end up returning the empty string instead of "0" if you passed in 0.
  • Slipp D. Thompson
    Slipp D. Thompson over 9 years
    @JonSkeet I'm not completely following why strings are involved in the first place. Or rather, a string. There are no other returns nor strings in the code sample.
  • Jon Skeet
    Jon Skeet over 9 years
    @SlippD.Thompson: The link in the question is to my DoubleConverter code - whose purpose is to convert a double into its exact string representation. Follow the link for the complete code.
  • Slipp D. Thompson
    Slipp D. Thompson over 9 years
    @JonSkeet I see now; you quoted a portion of the code the OP was unsure about. I'll admit I skimmed the english here and went straight to the code. ;-/ In the context of an SO answer, it wouldn't hurt to have a few extra lines of context. // Actually, I'll just do it. I hope you don't mind.
  • Xonatron
    Xonatron over 6 years
    Link needs updating.
  • D.R.
    D.R. over 5 years
    @JonSkeet: Your check for the sign bits < 0 is incorrect for the double value -0. You should, imho, instead check for (bits & (1<<63)) > 0.
  • Jon Skeet
    Jon Skeet over 5 years
    @D.R.: Thank you, yes. Fixed.
  • Mike Marynowski
    Mike Marynowski over 4 years
    @D.R. @JonSkeet Are those two statements not 100% equivalent? Both produce true for -0.0 and false for 0.0...or am I missing something here?
  • Mike Marynowski
    Mike Marynowski over 4 years
    I think @D.R. was thinking about the double d value and not the long bits value when he said that. If the 64th bit of a long is not zero then the long is negative so either should work fine :)
  • Michael
    Michael about 4 years
    I've run this code and I find that the correct way to "Bias the Exponent" is to do it after normalizing with the code: exponent = 1075 - exponent; This works correctly for the application I'm designing but I'm not sure why or if I'm making an error?
  • Jon Skeet
    Jon Skeet about 4 years
    @Michael: I suspect you're treating the exponent in the opposite way to the way I am, that's all. (Shift left vs shift right.)
  • Michael
    Michael about 4 years
    Thanks, yeah, this is all hazy to me but thanks for this example it was a life saver!
  • pogosama
    pogosama about 3 years
    Edit queue is full, so I'll put the updated link here: docs.microsoft.com/en-us/dotnet/api/system.double