2

PHP に次のコードがあります。ここでは、変数を整数に型キャストし、比較前にすべての値を 100 倍して浮動小数点エラーを回避して、小数点以下 2 桁を削除することで、前述の問題を解決しようとしました。

ただし、次のコードは依然として式を true と評価し、テキストを緑ではなく赤で色付けしますが、$eq_left と $eq_right の 2 つの値をエコーすると、小数点がなく同一です。

コードは次のとおりです。

$eq_left    = (int) ($eq_bal_CurrentAssets*100) + ($eq_bal_NonCurrentAssets*100) ;
$eq_right   = (int) ($eq_bal_Liabilities*100) + ($eq_bal_Taxation*100) + ($eq_bal_Equity*100) ;

if ($eq_left !== $eq_right) {
    $color = 'red';
    $diff   = abs($eq_left - $eq_right);
} else {
    $color = 'green';
}

echo "<div style=\"color: $color; font-weight:bold;\">\n";
echo "  " . number_format(($eq_left/100),2,".",",") . " = " . number_format(($eq_right/100),2,".",",") . "<br />\n";
if ($diff) {
    echo "      Difference = " . number_format(($diff/100),2,".",",") . "\n";
}
echo "</div>\n";
echo $eq_left . " | " . $eq_right

何か案は?

4

2 に答える 2

3

正確な小数表現が必要な場合は、浮動小数点に対する推奨事項に同意します。

その理由は、多くの小数はfloatまたはdoubleでしか概算できないためです。それらは、10進数ではなく、2進数の分数に基づいています。一般に、aとbに共通の因子がない有理数a / bは、bのすべての素因数がbの素因数でもある場合に限り、基数r表現で正確に表すことができます。たとえば、10進数では1/5は0.2ですが、1/3は0.333333333です...バイナリシステムでは、1/5は10進数の1/3と同じ問題を引き起こします。

あなたのコードでは、100を掛けた後、小数点以下をゼロに丸めることをお勧めします。(int)キャストはゼロに向かって丸めますが、これは必要なことではありません。入力が正の整数nより少しでも小さい場合、キャストの結果はn-1になります。ラウンドの結果はnです。

正確に表現できない小数の浮動小数点表現は、元の小数よりもわずかに低いか、わずかに高い可能性があります。たとえば0.29から始めて、それを最も近いIEEE 754 64ビット浮動小数点に変換し、100を掛けると、実際には28.999999999999996447286321199499070644378662109375に相当する浮動小数点が得られます。

これをゼロに丸めてintに変換すると、29ではなく28になります。最も近いintに丸めると、29になります。

于 2012-12-22T07:28:16.153 に答える
1

お金のために浮動小数点数を使用しないでください。 通貨の値は常に整数のセントとして格納します。$5.40 を 540 として保存し、表示するときに 100 で割ります。浮動小数点数は、あなたが考えている小数を正確に表すことはできません。

以下のページでは、フロートをお金として扱うのはひどい考えである理由について説明しています。

あなたが抱えている問題は、小数の浮動小数点表現に固有のものです。それらを確実に回避する唯一の方法は、整数を使用することです。

于 2012-12-22T05:06:17.407 に答える