【问题标题】:add two double given wrong result添加两个双给出错误的结果
【发布时间】:2009-07-28 11:59:39
【问题描述】:

我正在使用以下代码,但在某些神秘的情况下,添加的结果与预期的不同:

double _west = 9.482935905456543;
double _off = 0.00000093248155508263153;
double _lon = _west + _off;

// check for the expected result
Debug.Assert(_lon == 9.4829368379380981);
// sometimes i get 9.48293685913086 for _lon (which is wrong)

我在我的应用程序中使用了一些本机 DLL,我怀疑某些 DLL 是造成这种“错误计算”的原因,但我需要找出是哪一个。 谁能给我一个提示如何找出我的问题的根源?

【问题讨论】:

  • 我在这里所说的也适用于 double:stackoverflow.com/questions/1193554/…
  • 问题的根源是浮点精度设置错误。有人将浮点精度设置为 24 位,这会导致计算错误。使用 _fpreset 或 _controlfp(MSVC 运行时 dll 的)可以纠正这个问题,但谁首先设置这个精度仍然是个谜?
  • 另一个例子:0.8 + 0.4 = 1.2000000000000002
  • 其他简单示例:0.1 * 0.1 = 0.0100000000000000020.1 + 0.2 = 0.300000000000000040.1 * 0.2 = 0.0200000000000000040.1 - 0.3 = -0.199999999999999980.2 + 0.1 = 0.300000000000000040.2 * 0.1 = 0.0200000000000000040.2 * 0.2 = 0.040000000000000010.2 - 0.3 = -0.099999999999999980.3 - 0.2 = 0.099999999999999980.3 - 0.2 = 0.09999999999999998 @ :)

标签: c# .net floating-point double addition


【解决方案1】:

double 不完全准确,请尝试使用小数代替

使用双精度和浮点数优于十进制的优点是性能

【讨论】:

  • -1 Decimal 如何提供比Double 更好的性能?您的 CPU 知道如何处理 SinglesDoubles,但对 Decimal 的所有操作都必须在较慢的内存中进行。
  • @TT - 我不知道我是怎么做到的,但我完全误读了你的答案 - 抱歉! (-1) 已删除,+1 用于指出性能问题!
【解决方案2】:

起初我认为这是一个舍入错误,但实际上是你的断言是错误的。尝试添加您的计算的整个结果,而不需要您进行任何四舍五入。

试试这个:

using System;

class Program
{
    static void Main()
    {
        double _west = 9.482935905456543;
        double _off = 0.00000093248155508263153;
        double _lon = _west + _off;

        // check for the expected result
        Console.WriteLine(_lon == 9.48293683793809808263153);       
    }
}

尽管在未来需要避免通常与System.SingleSystem.Double 类型相关的舍入错误时,最好使用System.Decimal

话虽如此,但这里并非如此。通过在给定点任意舍入数字,您假设该类型也将在同一点舍入,这不是它的工作方式。浮点数以最大表示容量存储,只有达到该阈值后才会进行舍入。

【讨论】:

  • 我尝试使用小数,但是将双精度数转换为小数失败,因为小数会自动对给定值进行四舍五入。如何避免这种情况?
【解决方案3】:

问题是 Double 的精度只有 15 - 16 位(在你的例子中你似乎需要更高的精度),而 Decimal 的精度是 28 - 29。你如何在 Double 和 Decimal 之间转换?

【讨论】:

    【解决方案4】:

    你被四舍五入和精度问题所困扰。见this。十进制可能会有所帮助。转至here 了解有关转换和舍入的详细信息。

    来自 MSDN:

    当您将 float 或 double 转换为十进制时,源值将转换为十进制表示形式,并根据需要四舍五入到小数点后 28 位后最接近的数字。根据源值的值,可能会出现以下结果之一:

    如果源值太小而无法表示为小数,则结果为零。

    如果源值是 NaN(不是数字)、无穷大或太大而无法表示为小数,则会引发 OverflowException。

    【讨论】:

      【解决方案5】:

      您不能用二进制系统中的浮点数准确地表示十进制系统中的每个浮点数,这甚至与十进制数的“小”程度没有直接关系,有些数字只是不“适合”在 base-2 中很好。

      在大多数情况下,使用更长的位宽会有所帮助,但并非总是如此。

      要以Decimal(128 位浮点)精度指定常量,请使用以下声明:

      decimal _west = 9.482935905456543m;
      decimal _off = 0.00000093248155508263153m;
      decimal _lon = _west + _off;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-01-11
        • 1970-01-01
        • 1970-01-01
        • 2014-09-16
        • 2011-11-15
        • 2019-02-06
        • 2014-01-30
        相关资源
        最近更新 更多