整数値の取扱について


$a = 16.81;
$b = 100;

$result = $a * $b;

echo $result . "<br>";

$result = (int)$result;

echo "int後" . $result;

についてPHPで結果を出したところ、

1681
int後1680

という結果になります。perlでも同様の式を行うと同じ結果になります。

尚、$a = 16.82; の場合は意図した値 ( int後 1682 )になります。

この原因、対処法についてご存知の方はいらっしゃいますでしょうか?

回答の条件
  • 1人1回まで
  • 登録:2008/11/17 17:51:45
  • 終了:2008/11/17 19:55:27

ベストアンサー

id:zzz_1980 No.1

zzz_1980回答回数492ベストアンサー獲得回数642008/11/17 18:44:13

ポイント50pt

C言語で double を使ってもそうなりますが、これは

'16.81' を2進の浮動小数点に変換する際の誤差によるものです。

(マイナスの誤差がのって、だいたい1.68099999999999977263e+1になります。)

int への変換は小数点部の切捨てによっておこないますので100倍して小数部を切り捨てると1681にならず1680になってしまいます。

http://www.phppro.jp/phpmanual/php/language.types.float.html#war...

php には任意精度数学関数がありますので、これを利用すれば発生する誤差をコントロールできます。

'16.82'は変換するとプラスの誤差がのって、1.682000000000000028421709430404e+01 になりますので、100倍して切り捨てれば1682となり誤差がないように見えます。

その他の回答(1件)

id:zzz_1980 No.1

zzz_1980回答回数492ベストアンサー獲得回数642008/11/17 18:44:13ここでベストアンサー

ポイント50pt

C言語で double を使ってもそうなりますが、これは

'16.81' を2進の浮動小数点に変換する際の誤差によるものです。

(マイナスの誤差がのって、だいたい1.68099999999999977263e+1になります。)

int への変換は小数点部の切捨てによっておこないますので100倍して小数部を切り捨てると1681にならず1680になってしまいます。

http://www.phppro.jp/phpmanual/php/language.types.float.html#war...

php には任意精度数学関数がありますので、これを利用すれば発生する誤差をコントロールできます。

'16.82'は変換するとプラスの誤差がのって、1.682000000000000028421709430404e+01 になりますので、100倍して切り捨てれば1682となり誤差がないように見えます。

id:pahoo No.2

pahoo回答回数5960ベストアンサー獲得回数6332008/11/17 19:15:29

ポイント50pt

原因・対策については zzz_1980 さんが回答しているとおりです。

任意精度数学関数について補足します。


PHP4 以降では、--enable-bcmath を付けてコンパイルされている場合に、BCMath任意精度数学関数が利用できるようになります。

これを使い、下記のようにすることで問題は解決します。

<?php
$a = 16.81;
$b = 100;

//普通の乗算
$result = $a * $b;
echo "普通の乗算 = " . $result . "<br />\n";
$result = (int)$result;
echo "int後 = " . $result . "<br />\n";

//BCMathによる乗算
$result = bcmul($a, $b);
echo "BCMathによる乗算 = " . $result . "<br />\n";
$result = (int)$result;
echo "int後" . $result . "<br />";
?>
  • id:zzz_1980
    | php には任意精度数学関数がありますので、これを利用すれば発生する誤差をコントロールできます。
    ではあまりに能がないですね。げたをはかせて固定小数点として扱い、任意精度数学関数かgmp関数をつかって必要な有効桁を確保して計算するのが一番かと思います。
  • id:yamadakouzi
    yamadakouzi 2008/11/17 20:34:15
    intは整数切捨ての関数です。基本です。
  • id:yamadakouzi
    yamadakouzi 2008/11/17 20:45:33
    16.81は100倍しても1681にはならず1680.99999・・・・xxとなり、16.82は100倍すると1682.00000xxxになります。これはコンピュータが計算用メモリーに格納する時、2進数(あるいは16進数等)に変換する時に一番近い2進数にするからです。
    ためしに、小数点の付く10進数を2進数に直して確かめてみてください。大きくなったり、小さくなったりします。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません