You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中获取IEEE-754浮点数的精确无缩放尾数

我所说的“精确”是指IEEE-754无法精确表示十进制数,这似乎是问题的核心。

所有十进制数都可以用科学计数法表示,如下所示。我添加了“无缩放值”列,即把所有有效数字移到小数点左侧后的十进制值;例如:

常规形式科学计数法无缩放值
0.011.01e+0101
0.0252.5e-225
1231.23e+2123
123456781.2345678e+712345678
123.4561.23456e+2123456
12345.6789012345671.2345678901234567e+412345678901234567
System.Double.MaxValue1.7976931348623157e+30817976931348623157 * (10 ^ 308)

以下代码利用.NET 7.0泛型数学分别从IEEE-754值中获取指数和尾数。请注意,它们获取的是十进制(基10)的指数和尾数,而非其二进制(基2)表示:

GetExponent

private static T GetExponent<T>(T value) where T : IBinaryFloatingPointIeee754<T>
{
    if (T.IsNaN(value) || T.IsInfinity(value) || T.IsZero(value)) return T.Zero;

    T absValue = T.Abs(value);
    T log10 = T.Log10(absValue);
    return T.Floor(log10);
}

GetMantissa

private static T GetMantissa<T>(T value) where T : IBinaryFloatingPointIeee754<T>
{
    T ten = T.CreateChecked(10);
    T exponent = GetExponent(value);
    T factor = T.Pow(ten, exponent);
    return value / factor;
}

基于上述表格,这些函数会生成以下值:

科学计数法尾数指数
1.01e+01.010
2.5e-22.5-2
1.23e+21.232
1.2345678e+71.23456787
1.23456e+21.234562
1.2345678901234567e+41.23456789012345674
1.7976931348623157e+3081.7976931348623157308

目前一切顺利!现在我希望将尾数乘以10,直到所有有效数字都移到小数点左侧。以下函数用于获取无缩放尾数:

private static BigInteger GetUnscaledMantissa<T>(T value) where T : IBinaryFloatingPointIeee754<T>
{
    T ten = T.CreateChecked(10);
    T mantissa = GetMantissa(value);
    T factor = T.One;

    // While the remainder isn't zero...
    while (mantissa * factor % T.One != T.Zero)
    {
        // ..multiply factor by 10.
        factor *= ten;
    }
    
    BigInteger result = BigInteger.CreateChecked(mantissa * factor);

    // trim any trailing zeros, which sometimes occurs.
    while (result % 10 == 0) result /= 10;

    return result;
}

我们来看一下结果:

尾数无缩放值
1.01101
2.525
1.23123
1.234567812345678
1.23456123456
1.234567890123456712345678901234566
1.797693134862315717976931348623158

总体而言,GetUnscaledMantissa函数返回的值是正确的,但请注意加粗标注的异常值;它们并不完全正确,似乎在某些情况下数值会被向上或向下舍入。

问题

虽然我理解这是IEEE-754二进制浮点数的固有特性,但有没有办法,或者说我该如何修改GetUnscaledMantissa函数,使其能够在所有情况,或至少更多/大多数情况下准确返回无缩放尾数?

(注:我知道这是可行的,只是并不简单)

更新

鉴于关于该主题的深入讨论,似乎大家对我的目标存在一些误解,希望以下内容能澄清这一点。

暂时忘掉IEEE-754!我们只关注纯数学。

以下数字以科学计数法表示,及其对应的完整形式:

表A

科学计数法完整形式
1.00001e+50100001000000000000000000000000000000000000000000000
-3.345233391e+45-3345233391000000000000000000000000000000000000
1.7976931348623157E+3081797693134862315700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

这些科学计数法表示的值数学上是准确的!

现在,误解似乎出现在用IEEE-754表示相同数字时的情况。

以下数字以科学计数法表示,及其对应的完整形式,但这次完整数字是基于IEEE-754计算得出的:

表B

科学计数法完整形式
1.00001e+50100000999999999993488106414884841393099338118332416
-3.345233391e+45-3345233391000000093465768949128568879123005440
1.7976931348623157E+308179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368

我希望GetUnscaledMantissa返回的是数学上正确的无缩放数字(表A中的值),而非IEEE-754“正确”的无缩放数字(表B中的值)。


内容的提问来源于stack exchange,提问作者Matthew Layton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:12:08