2

重複の可能性:
C コンパイラのバグ (浮動小数点演算)?

小数点以下 150 桁に正確に等しいことを保証できる double が 2 つあります。次のコード:

printf("***current line time is %5.150lf\n", current_line->time);
printf("***time for comparison is %5.150lf\n", (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS));

...戻り値:

***current line time is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
***time for comparison is 39346.526736111096397507935762405395507812500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

FIVE_MINUTES_IN_DAYSは #defined であり、current_line->timelast_stage_four_print_timeは両方とも double です。

私の問題は、デバッグ コードの次の行です。

printf("if condition is %d\n", (current_line->time >= (last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)));

以下を返します。

if condition is 0

ここで何が起こっているのか誰か教えてもらえますか? floatsandの非 10 進数/不正確な性質を認識してdoublesいますが、これらはまったくエラーの対象ではありません (元の数値はすべてsscanfまたは #define で読み取られ、すべて小数点以下 10 桁まで指定されています)。

編集:私の間違いは、ダブルスをメモリ内で正確に表現すると仮定してprintfいましたが、1つの値がオンザフライで計算されているため、これは間違っていました。(last_stage_four_print_time + FIVE_MINUTES_IN_DAYS)asを宣言してthreshold_timeそれを使用すると、問題が解決しました。比較には必ずイプシロンを使用します。それが正しい方法であることはわかっていましたが、(誤って)同じように見えると思っていたこれらの値が明らかに等しくない理由について混乱していました。

4

6 に答える 6

4

浮動小数点表現について読んでください (特にhttp://en.wikipedia.org/wiki/IEEE_754-2008 )。double を含むバイトの実際の内容を 16 進数で出力してみてください。ビットごとに一致しません。float の適切な比較は、Knuth (半数値アルゴリズム) にあります。単純に (bool を int に、float を double に、true を 1 に置き換えます):

bool almostEqual(float x, float y, float epsilon)
{
    if (x == 0.0 && y == 0.0) {
        return true;
    }

    if (fabs(x) > fabs(y)) {
        return fabs((x - y) / x) < epsilon;
    } else {
        return fabs((x - y) / y) < epsilon;
    }
}
于 2012-04-04T07:00:54.323 に答える
4

浮動小数点数は確かに有効数字 150 桁まで正確ではないため、「視覚的な」比較 (存在する場合) からどのような結論を引き出すことができるかわかりません。

一方、値は明らかにビット同一ではありません (そして、そのうちの 1 つが追加でその場で計算されるため、どのように同一である可能性がありますか?)。したがって、表示される動作が予期しないものである理由は明確ではありません。

そのようなフロートを比較しないでください。違いとイプシロンの標準的な比較を行うだけです。

于 2012-04-04T06:58:01.610 に答える
3

float と double を比較して等しいかどうかを確認するには、常に EPSILON 値を使用する必要があります。同じように見えても、これらのタイプの数値は 2 進数で表現されるため、内部表現が一致するとは限りません。

次のようなことができます

#define EPSILON 0.00001
...
if (fabs(a - b) <= EPSILON) return 1; // they are equal
return 0;
于 2012-04-04T06:56:28.063 に答える
2

イエスはこれを解決する方法について正しい.

理由については... ある場合は定数値を読み込み、別の場合は加算演算を実行します。印刷出力がまったく同じであっても、バイナリ表現はわずかに異なる場合があります。

2 つの double をサポートするメモリを調べて、ビットが異なるかどうかを確認してください (違いはあります)。

包括的な治療のために、私はお勧めします

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

于 2012-04-04T06:59:23.557 に答える
1

通常、float や double を比較するために == を使用するべきではありません。代わりに、差が小さな数よりも小さいことを確認する必要があります。

double second_number = last_stage_four_print_time + FIVE_MINUTES_IN_DAYS;
if (fabs(current_line->time - second_number) < 0.001 || current_line->time > second_number){
  // your comparison code
}
于 2012-04-04T06:59:26.373 に答える
1

まず、double の小数点以下の桁数はわずか 15 ~ 16 です (52 ビットマティッサの log_2)。

次に、比較する場合は、前述のイプシロンを使用します。

3 番目に、デバッグのために、16 進値を出力します。

于 2012-04-04T07:00:43.537 に答える