c ++产生错误的计算结果。这可以纠正吗?

时间:2013-10-15 03:22:08

标签: c++ kubuntu

我在“Ask Ubuntu”论坛上询问了以下问题,并被告知该问题不适合该论坛。有人建议我在这里问我的问题。如果这不是这个问题的适当场所,我会提前道歉。

我目前使用java作为我的默认语言。此外,我目前正在运行Kubuntu版本12.04。我正在将一个c ++程序转换为java,而java程序的结果与c ++程序的结果不匹配。当我意识到java程序产生了正确的结果并且c ++程序没有产生正确的结果时,我开始四处寻找问题。我的问题是,任何人都可以解释为什么c ++会产生错误的结果并且可以修复吗?

我写了两个最小程序来说明问题。我还写了一个脚本文件来显示这两个程序,编译并运行它们。结果如下。显然,有效数字位于相同的邻域中,但是当处理诸如30次幂的10​​的大功率时,差异是显着的。以下是我的测试程序和脚本的结果:

Linux Pegasus 3.2.0-54-generic#82-Ubuntu SMP Tue Sep 10 20:08:42 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux

c ++ source

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    double testValue;
//---------------------------------------------------------------------
    testValue = 1.0e0 * 1.9891e30;

    cout << scientific << showpoint << right << setprecision(20)
      << "The test value = "
      << setw(25) << testValue
      << "  the test value should be 1.9891e30\n"
      << endl;

    return 0;
}

java源

class test
{
    public static void main (String[] args)
    {
    double testValue;
    //---------------------------------------------------------------------
    testValue = 1.0e0 * 1.9891e30;

        System.out.format 
        (
            "The test value = %.20e  the test value should be 1.9891e30%n", testValue
        );
    }   // end main
}

g ++ test

测试值= 1.98909999999999988781e + 30测试值应为1.9891e30

java test

测试值= 1.98910000000000000000e + 30测试值应为1.9891e30

显然,c ++程序生成的testValue的值是错误的,而java程序生成的testValue的值是正确的。任何和所有洞察这个问题将不胜感激。我搜索谷歌和这里使用搜索词“c ++错误计算”没有任何重要发现。

2 个答案:

答案 0 :(得分:0)

我不确定你觉得这个计算是错误的?浮点数学受到值的微小差异的影响。在具有单个编译器的单个机器上,浮点值是确定性的,但是,对于不同的语言和不同的编译器,您不能保证具有相同的结果。

我的老教授布鲁斯道森给出了一个很好的概述: http://randomascii.wordpress.com/2012/04/05/floating-point-complexities/ http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

您在上面看到的结果对我来说很合适。也许您应该在小数点后舍入到3位数并使用它来比较结果值。对于浮点,您将很难在不同语言和编译器之间更准确地使用它。

此外,我建议下次使用“浮点不准确”作为更好的Google搜索。

答案 1 :(得分:0)

当Java代码对值进行四舍五入时,C ++代码将打印出实际值。请注意,0.00010.1一样,无法用二进制表示。

您可以使用BigDecimal来打印实际值,这与您的C ++输出相同:

import java.math.*;
class test
{
public static void main (String[] args)
{
    double testValue;
    testValue = 1.0e0 * 1.9891e30;

    BigDecimal realvalue = new BigDecimal(testValue);
    System.out.format
    (
    "The test value = %.20e the test value should be 1.9891e30%n", realvalue
    );
}
}

<强>输出

  

测试值= 1.98909999999999988781e + 30应为测试值   1.9891e30

AFAIK,C ++和Java中的double都将保持相同的值,但是当打印出来时,你会看到差异。