【问题标题】:Comparing two fixed doubles with <, =, >. Is there really an issue?用 <, =, > 比较两个固定双精度。真的有问题吗?
【发布时间】:2015-06-16 06:20:47
【问题描述】:

我想检查一个double 是小于、等于还是大于另一个double。尽管我读了很多关于floatsdoubles 的内容由于计算机如何在二进制级别上计算而无法精确比较,但到目前为止,使用简单的二进制运算符就像一个魅力。我用几十个不同的数字对其进行了测试,到目前为止,它甚至没有让我失望过一次。

那么就我而言,像这样比较它们真的有问题吗?如果有 - 为什么我找不到它以及如何修复它?

编辑:如果我决定比较它们,我知道0.1 + 0.2 != 0.3。问题是 - 我想简单地比较两个 fixed doubles。我不必比较0.1 + 0.20.3。我最多只能比较0.30.3。或0.40.3。类似的东西。我真的需要使用 BigDecimal、epsilon 或其他什么吗?

【问题讨论】:

  • 如果和=比较肯定会遇到问题。 == 的情况较少,但仍然存在问题。另外,查看stackoverflow.com/q/588004/1288 的具体示例。
  • @BiltheLizard 我已经看到了。问题是..我只是有两个固定的(!)双数..我没有做任何操作,而是对它们进行比较。这就是我的问题的来源!也编辑了我的 OP!
  • double 真正相等的也将真正比较相等(NaN 除外)。
  • == 运算符确实比较双精度值是否相等。如果您分配x=0.3,那么x == 0.3 将是true。以下所有否定答案都正确地警告您,程序员经常将错误引入代码中,将double视为一种真实,并错误地期望特定结果来自某些特定情况下的一些计算。 (例如,如果你认为for(x=0.0;x!=0.3;x+=0.1) 会终止,请再想一想!)明智地 使用==,并使用单元测试和asserts 向其他程序员证明你知道你在做什么。

标签: java numbers compare theory point


【解决方案1】:

double完全可比的。出现问题主要有两个原因

  1. 许多人认为double 的数学运算与Reals 的数学运算相同。它不是。许多关于事物应该完全相等的假设并不容易(或根本不)从 Reals 转换为 double's。
  2. “有趣的事情”,例如不可预知的扩展精度激活(使用strictfp

像往常一样,其他答案都是错误的。 double 不“代表”一系列数字(您可以假装他们这样做,但最终 double 只有一个确切的值,并且不知道它要代表什么样的“范围”)。表明double 的相等性可以产生“有趣的结果”的答案是正确的,只要结果是“有趣的”,但问题在于预期结果,而不是结果本身。如果您期望正确的事情,那没有问题。

【讨论】:

  • 哦?运行它并告诉我们你得到了什么:#include &lt;limits.h&gt; #include &lt;stdio.h&gt; #include &lt;sys/types.h&gt; int main( int argc, char **argv ) { uint64_t ii = UINT64_MAX; double aa = (double) ii/0.0001; ii--; double bb = (double) ii/ 0.0001; if ( aa == bb ) printf( "Hey, they're \"equal\"!\n" ); return( 0 ); } 说双精度值“不“代表”一个数字范围”充其量是不诚实的。对于每个“精确”双精度值,都有一个实数范围,只能由该值表示。
  • @AndrewHenle 当然,有一个范围最接近任何给定的双精度(嗯,除了无穷大和 nan)。这也适用于整数。这并不意味着它们中的任何一个都范围,如果您以这种方式解释它们,那么这仅仅是一种解释(并且是一种危险的解释)。
【解决方案2】:

&lt;&gt; 运算符不是问题。

== 运算符将对任何真实数据产生问题。所以你还没有遇到问题?好吧,你可以在雷暴期间在高尔夫球场上跑来跑去,在头顶挥舞球杆,也不会被闪电击中。不代表你不会。

【讨论】:

    【解决方案3】:

    这是一个使用浮点数会导致错误的示例。

    System.out.println(1.0 - 0.2 - 0.3 - 0.4 - 0.1); // Is not 0.0
    

    如果您需要任意精度的十进制数,请使用BigDecimal

    【讨论】:

      【解决方案4】:

      doubles 是十进制数的离散表示。这意味着并非所有数字都可以用双精度表示。

      例如,double 不能准确地表示一些非常大的数字,在这种情况下,它们会“四舍五入”到最接近的可用双精度数。例如:

      public static void main(String[] args) {
        double d1 = 1e50;
        double d2 = d1 + 1;
        System.out.println(d2 > d1); //false
        System.out.println(d2 == d1); //true
      }
      

      【讨论】:

      • @user3213110 我对您的编辑的回答是一样的:在我的示例中,您可能期望 d2 大于 d1,但它不是从 Java 的角度来看的。这可能是也可能不是您正在做的事情。
      猜你喜欢
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多