简体   繁体   English

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

[英]Extracting mantissa and exponent from double in c#

Is there any straightforward way to get the mantissa and exponent from a double in c# (or .NET in general)?有什么直接的方法可以从 c#(或一般的 .NET)中的双精度数中获取尾数和指数?

I found this example using Google, but I'm not sure how robust it would be.我使用 Google 找到了这个示例,但我不确定它的可靠性如何。 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.我发现的另一种选择是使用 System.Decimal 而不是 double 并使用Decimal.GetBits()方法来提取它们。

Any suggestions?有什么建议么?

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.正如吉米所说,它被定义为 IEEE754 / IEC 60559:1989 格式。 (C# 3.0 language spec section 1.3; ECMA 335 section 8.2.2). (C# 3.0 语言规范第 1.3 节;ECMA 335 第 8.2.2 节)。 The code in DoubleConverter should be fine and robust. DoubleConverter 中的代码应该很好而且很健壮。

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.在第一部分之后,您已经获得了“原始”指数和尾数 - 其余代码只是帮助以更简单的方式处理它们。

The representation is a IEEE standard and shouldn't change.该表示是 IEEE 标准,不应更改。

https://msdn.microsoft.com/en-us/library/system.double(v=vs.110).aspxhttps://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. Double 类型符合 IEC 60559:1989 (IEEE 754) 二进制浮点运算标准。

EDIT: The reason why decimal has a getBits and double does not is that decimal preserves significant digits.编辑:decimal 有 getBits 而double 没有的原因是decimal 保留了有效数字。 3.0000m == 3.00m but the exponents/mantissas are actually different. 3.0000m == 3.00m 但指数/尾数实际上是不同的。 I think floats/doubles are uniquely represented.我认为浮动/双打是唯一代表。

I can think of another way by using double.ToString("E17") and parsing the resulting scientific notation string.我可以通过使用double.ToString("E17")并解析生成的科学记数法字符串来想到另一种方法。 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM