在c#中从double中提取尾数和指数

时间:2008-12-23 20:26:11

标签: c# .net floating-point

有没有直接的方法从c#(或一般的.NET)中获取双尾数和指数?

我发现this example使用谷歌,但我不确定它会有多强大。二进制表示可以在框架的某个未来版本中进行双重更改吗?

我发现的另一个选择是使用System.Decimal而不是double,并使用Decimal.GetBits()方法来提取它们。

有什么建议吗?

3 个答案:

答案 0 :(得分:28)

二进制格式不应该改变 - 它肯定会对现有规范进行重大改变。吉米说,它被定义为IEEE754 / IEC 60559:1989格式。 (C#3.0语言规范1.3节; ECMA 335节8.2.2)。 DoubleConverter中的代码应该很好而且健壮。

为了将来参考,示例中代码的相关位是:

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++;
    }

    …
}

这些评论当时对我有意义,但我相信我现在必须考虑一下。在第一部分之后,您已经获得了“原始”指数和尾数 - 其余代码只是以更简单的方式处理它们。

答案 1 :(得分:1)

表示是IEEE标准,不应更改。

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

  

Double类型符合IEC 60559:1989(IEEE 754)二进制浮点运算标准。

编辑:十进制有getBits和double的原因是十进制保留有效数字。 3.0000m == 3.00m但指数/尾数实际上是不同的。我认为花车/双打是唯一的代表。

答案 2 :(得分:0)

我可以想到另一种方法,即使用 double.ToString("E17") 并解析生成的科学记数法字符串。但是如果double的有效数字太多,这种方法提取尾数就会不准确。

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;
    }
}

像这样使用上面的类:

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