31

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?

4

3 回答 3

34

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.

于 2008-12-23T21:03:08.710 回答
1

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.

于 2008-12-23T20:30:23.940 回答
-1

I can think of another way by using double.ToString("E17") and parsing the resulting scientific notation string. But this method will be inaccurate for the mantissa extraction if the double has too many significant digits.

public class DoubleParser
{
    public static int GetExponent(double d)
    {
        var doubleParts = ExtractScientificNotationParts(d);
        return Convert.ToInt32(doubleParts[1]);
    }

    public static double GetMantissa(double d)
    {
        var doubleParts = ExtractScientificNotationParts(d);
        return Convert.ToDouble(doubleParts[0]);
    }

    private static string[] ExtractScientificNotationParts(double d)
    {
        var doubleParts = d.ToString(@"E17").Split('E');
        if (doubleParts.Length != 2)
            throw new ArgumentException();

        return doubleParts;
    }
}

Use the class above like so:

var value1 = 43948530544.3433;
var mantissa = DoubleParser.GetMantissa(value1);  // 4.39485305443433
var exponent = DoubleParser.GetExponent(value1);  // 10

var value2 = 0.00000000009869232667160136;
mantissa = DoubleParser.GetMantissa(value2);  // 9.8692326671601371
exponent = DoubleParser.GetExponent(value2);  // -11
于 2021-04-12T21:50:47.110 回答