6

重複の可能性:
10進数を2進数で正確に表すことができないのはなぜですか?
浮動値の問題

$var1 = 1;

for ( $i=0; $i<30; $i++ ) {
  $var1 += 0.1;
  $var2 = floor($var1);
  $var3 = $var1-$var2;
  if ( $var3 == 0.5 ) {
    $var1 = $var2+1;
  }
}

このループの目的は、1.0、1.1、1.2、1.3、1.4をカウントしてから、2.0、2.1、2.2などにジャンプすることです。

私が得ている問題は、そのif声明が決して真実ではないということです。また、10回ごとの計算は、いくつかの非常識な科学的答えに解決されます。

これを修正するにはどうすればよいですか?助けてください!

編集:私は少しイライラしたラッシュで質問を書きました、そしてそれは複数でした、私は今それを見ます。

質問の最初の部分は、実際には「この浮動小数点クエルクをバイパスしてこの作業を行うにはどうすればよいか」と「なぜこのクエルクが発生するのか」でした。

素晴らしい返信をありがとうございました。「これを機能させる方法」という主要な質問に簡単に答えられる正解に投票します。

0.5の代わりに0.49を使用し、==の代わりに>を使用します。原油であり、世界で最高のコードではありませんが、元の質問を解決します。コーディングを改善するために読んでフォローアップする他の回答をありがとうございました。

もう一度、どうもありがとう。

4

7 に答える 7

5

コンピューターは2進数(基数2)で格納されているため、浮動小数点数を正確に表すことはできません。すべてのフロートには、これまでにないわずかな調整+/-があります。

ここを参照してください:http ://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

于 2012-07-06T17:03:53.920 に答える
5

これは望ましい結果をもたらします:

$var1 = 1;
for ( $i=0; $i<30; $i++ ) {
    $var1 += 0.1;
    $var2 = (int)($var1);
    $var3 = $var1-$var2;
    if ( $var3 >= 0.45 ) {
        $var1 = $var2+1;
    }
    echo $var1.' '.$var2.' '.$var3.'<br/>';
}
于 2012-07-06T17:12:12.793 に答える
3

2進浮動小数点は、表現できない10進数の浮動小数点を表す近似値を選択します。したがって、floatとfloatを比較することは正確ではありません(その動作を判別できないため)。

独自の10進数の浮動小数点を発明する必要があります。あなたがどれを正確に望むかを知っていれば、発明するのは難しいことではありません。あなたの場合、あなたはたった1桁の正確な数字を必要とするでしょう。基数10の整数の式は次のようになります。値/10の正確な桁の累乗である1であるため、式は=値/10になります。

算術演算の実行は、通常の算術演算と同じくらい簡単です。通常の表現(コンピューターが使用する表現を指す)を私たちが発明した表現に変換するだけです。あなたの場合、$var1 += 0.1になります$var1 += 1

出力は、表現を通常の表現に変換するのと同じくらい簡単です。あなたの場合echo $var1 . '<br>';echo $var1 / 10 . '<br>';

$var1 = 10;

for ( $i=0; $i<30; $i++ ) {
  echo $var1 / 10 . '<br>';
  $var1 += 1;
  if ($var1 % 10 == 5) {
    $var1 = $var1+5;
  }
}
于 2012-07-06T17:15:31.887 に答える
2

これが発生する理由といくつかの解決策に関する多くの良い情報。PHPの基本的な設計目標の1つは、ルーズタイプの設計と暗黙的なキャストです。その精神で、この問題の最も簡単な解決策の1つは、文字列比較を使用することだと思います。あなたの場合、それは素晴らしい解決策です:

<?php
$var1 = 1;

for ( $i=0; $i<30; $i++ ) {
  $var1 += 0.1;
  $var2 = floor($var1);
  $var3 = $var1 - $var2;
  echo "$var1 | $var2 | $var3 \n";
  if (number_format($var3, 1) == '0.5') {
    echo "It's true\n";
    $var1 = $var2 + 1;
  }
}
于 2012-07-06T17:27:12.247 に答える
1

適切な解決策は、bcmathパッケージを使用することです。

$var1 = '1.0'; bcscale(1);

for ( $i = 0; $i < 30; $i++) {
    $var2 = $var1;
    for( $j = 0; $j < 5; $j++) {
        echo $var2 . "\n"; 
        $var2 = bcadd( $var2, '0.1');
    }
    $var1 = bcadd( $var1, '1');
}

これにより、正しい結果が出力されます

于 2012-07-06T17:19:16.743 に答える
0

ifステートメントは、一般に浮動小数点演算のために実行されることはありません。浮動小数点値との厳密な同等性のテストには、常にこのリスクが伴います。条件を変更して、変数が0.5を中心とする小さな間隔内にあることを確認して、確実にキャッチできるようにしてみませんか?

于 2012-07-06T17:05:09.977 に答える
-1

シンプルで愚かで、整数演算を使用してください。

たとえば、1.1から始めます

なぜだめですか:

for ( $i=1; $i<4; $i++ ) {
  for ( $j=0; $j<5; $j++ ) {
    $v = $i + ($j/10);
    # ...
  }
}
于 2012-07-06T17:08:45.067 に答える