C#中的双重比较精度损失,加减双精度时发生精度损失

Double comparison precision loss in C#, accuracy loss happening when adding subtracting doubles

刚开始学习 C#。我计划将它用于繁重的数学模拟,包括数值求解。问题是我在添加和减去 double 时以及比较时会出现精度损失。代码及其内容returns(在评论中)如下:

namespace ex3
{
    class Program
    {
        static void Main(string[] args)
        {

            double x = 1e-20, foo = 4.0;

            Console.WriteLine((x + foo)); // prints 4
            Console.WriteLine((x - foo)); // prints -4
            Console.WriteLine((x + foo)==foo); // prints True BUT THIS IS FALSE!!!
        }
    }
}

非常感谢任何帮助和说明!

让我不解的是 (x + foo)==foo returns True.

查看 double 的 MSDN 参考:https://msdn.microsoft.com/en-AU/library/678hzkk9.aspx

表示double的精度为15到16位。

但是 1e-204.0 之间的位数相差 20 位数。尝试在 4.0 中添加或减去 1e-20 的行为仅仅意味着 1e-20 丢失了,因为它不适合 15 到 16 位精度。

因此,就 double 而言,4.0 + 1e-20 == 4.04.0 - 1e-20 == 4.0

您要查找的可能是十进制结构 (https://msdn.microsoft.com/en-us/library/system.decimal.aspx)。 Doubles 无法以您正在寻找的精度正确表示那种值 (C# double to decimal precision loss)。相反,尝试使用 Decimal class,像这样:

decimal x = 1e-20M, foo = 4.0M;

        Console.WriteLine(Decimal.Add(x, foo)); //prints 4,0000000000000000001
        Console.WriteLine(Decimal.Add(x, -foo)); //prints -3,9999999999999999999
        Console.WriteLine(Decimal.Add(x, foo) == foo); // prints false

对 Enigmativity 答案的补充:

要做到这一点,您需要更高的精度,decimal 精度为 28 到 29 位,基数为 10:

decimal x = 1e-20m, foo = 4.0m;
Console.WriteLine((x + foo)); // prints 4.00000000000000000001
Console.WriteLine((x - foo)); // prints -3.99999999999999999999 
Console.WriteLine((x + foo) == foo); // prints false.

但请注意,小数确实具有更大的 精度,但具有较低的 范围。查看有关十进制的更多信息 here

这不是 C# 的问题,而是您的计算机的问题。它并不复杂或难以理解,但需要阅读很长时间。如果您想真正深入了解计算机的工作原理,您应该阅读 this article

一个优秀的 TLDR 站点 恕我直言,比上述文章更能介绍该主题 是这篇文章:

http://floating-point-gui.de/


我将为您提供一个非常简短的解释,说明正在发生的事情,但您当然应该至少阅读该网站,以避免将来出现麻烦,因为您的应用领域需要深入了解此类知识。

情况如下:您有 1e-20,它比 1.11e-16 小。另一个数字在您的计算机上称为双精度机器 epsilon(最有可能)。如果您将等于或大于 1 的数字添加到小于机器 epsilon 的某个值,它将被四舍五入,回到大数字。这是由于 IEEE 754 表示。这意味着在加法发生后,结果为 "correct"(就像你有无限精度),结果以 limited/finite 精度的格式存储,舍入 4.00....001到4,因为四舍五入的误差小于1.11e-16,所以可以接受。