1

「Ask Ubuntu」フォーラムで次の質問をしたところ、その質問はそのフォーラムには不適切だと言われました。ここで質問するように言われました。これがこの質問の適切な場所でない場合は、事前にお詫び申し上げます。

現在、Java をデフォルト言語として使用しています。また、現在 Kubuntu バージョン 12.04 を実行しています。C++ プログラムを Java に変換していましたが、Java プログラムの結果が C++ プログラムの結果と一致しませんでした。Java プログラムが正しい結果を生成し、c++ プログラムが正しい結果を生成していないことに気付いたとき、私は問題を探し始めました。私の質問は、なぜ c++ が誤った結果を生成するのか、それを修正できるのかを説明できる人はいますか?

この問題を説明するために、2 つの最小限のプログラムを作成しました。また、2 つのプログラムを表示し、コンパイルして実行するためのスクリプト ファイルも作成しました。結果は以下のとおりです。明らかに有効桁数は同じ付近にありますが、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++ ソース

#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++ テスト

テスト値 = 1.98909999999999988781e+30 テスト値は 1.9891e30 である必要があります

ジャバテスト

テスト値 = 1.9891000000000000000e+30 テスト値は 1.9891e30 である必要があります

明らかに、c++ プログラムによって生成された testValue の値は間違っていますが、Java プログラムによって生成された testValue の値は正しいです。この問題に関するすべての洞察は、非常に高く評価されます。私はグーグルを検索しましたが、ここでは「c ++の誤った計算」という検索用語を使用して、重要な発見はありませんでした。

4

2 に答える 2

0

この計算が間違っていたとあなたがどのように感じているかわかりませんか? 浮動小数点演算は、値のわずかな違いの影響を受けます。単一のコンパイラを備えた単一のマシンでは、浮動小数点値は決定論的ですが、異なる言語や異なるコンパイラを使用すると、同じ結果が得られるとは限りません。

私の古い教授であるブルース・ドーソンが素晴らしい概要を 説明しています: http://randomascii.wordpress.com/2012/04/05/floating-point-complexities/ 点決定論/

上記の結果は、私には問題ないように見えます。おそらく、小数点以下 3 桁に丸め、それを使用して結果の値を比較する必要があります。浮動小数点を使用すると、異なる言語やコンパイラ間でより正確にするのは難しいでしょう。

また、次回はより良いGoogle検索として「浮動小数点の不正確さ」をお勧めします。

于 2013-10-15T04:10:15.553 に答える
0

Java コードが値を丸めている間、C++ コードは実際の値を出力しています。数値を 2 進数で正確に表すことはできないことに注意し0.0001てください。0.1

BigDecimalC++ 出力と同じになる実際の値を出力するように取得できます。

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 である必要があります

私の知る限り、doubleC++ と Java ではどちらも同じ値を保持しますが、それらを印刷すると違いがわかります。

于 2013-10-15T04:35:25.633 に答える