与 int 相乘的双倍在 .NET Core 中变得不太准确

问题描述 投票:0回答:1

我正在使用不同版本的 .NET 尝试此代码块:

using System;
using System.Linq;
                    
public class Program
{
    public static void Main()
    {
        Decimal decimalVal = 9.38M;
        Double doubleVal = 9.38;
        Single singleVal = 9.38F;
        Int32 i = 100;
        
        Console.WriteLine(decimalVal*i); // "938.00"
        Console.WriteLine(doubleVal*i); // .NET Core+: "938.0000000000001". .NET Framework 4.7.2: "938"
        Console.WriteLine(singleVal*i); // "938"
        
        var doubleResult = doubleVal*i;
        
        var doubleBytes = BitConverter.GetBytes(doubleResult);
        var str = string.Join(" ", doubleBytes.Select(x => Convert.ToString(x, 2).PadLeft(8, '0')));
        
        Console.WriteLine(str);
        // Same value for .NET Core+ and .NET Framework 4.7.2:
        // 00000001 00000000 00000000 00000000 00000000 01010000 10001101 01000000

        Console.WriteLine(BitConverter.IsLittleEndian); // "True", in case it's important to know?
    }
}

为什么

9.38*100
在 .NET Framework 4.7.2 中生成准确的
938
值,但在 .NET Core 3.1 及更高版本中,它生成
938.0000000000001

我查看了用于表示数字的实际位,无论使用哪个 .NET 版本,这些位都是相同的。

顺便说一句,差异可能早于 .NET Core 3.1 开始,但我只测试了 https://dotnetfiddle.net 上可用的内容。

.net .net-core floating-point double precision
1个回答
0
投票

这并不是乘法结果的变化。这是默认字符串格式的更改 - 使生成的字符串能够更准确地表示结果。

这是代码的另一个版本,这次使用我的 DoubleConverter 代码以十进制形式显示 double

精确
值:

using System;

class Program
{
    static void Main()
    {
        double initial = 9.38;
        double actualResult = initial * 100;
        double literal1 = 938.0000000000001;
        double literal2 = 938;
        Console.WriteLine($"Actual result ToString: {actualResult}");
        Console.WriteLine($"Actual result exact value: {DoubleConverter.ToExactString(actualResult)}");
        Console.WriteLine($"Equal to literal 938.0000000000001? {actualResult == literal1}");
        Console.WriteLine($"Equal to literal 938? {actualResult == literal2}");
    }
}

.NET 8.0 的结果:

ctual result ToString: 938.0000000000001
Actual result exact value: 938.0000000000001136868377216160297393798828125
Equal to literal 938.0000000000001? True
Equal to literal 938? False

.NET 4.8 的结果:

Actual result ToString: 938
Actual result exact value: 938.0000000000001136868377216160297393798828125
Equal to literal 938.0000000000001? True
Equal to literal 938? False

在我看来,.NET 8.0 结果更好 - 基本上,如果您采用 ToString

output
,并将其用作代码中的
double
文字,您最终会得到与乘法的结果。对于 .NET 4.8 来说并非如此。

© www.soinside.com 2019 - 2024. All rights reserved.