2010年9月 6日

[PHP-users 35361] Re:小数点以下を含まない ceil()の実行結果

中島と申します

> $a=2*10770*1.35;
> echo $a; // 29079
> echo ceil($a); // 29080
この浮動小数点における切り上げ・切り捨ての問題は
変数型キャストの問題、PHPだけの問題ではないとは思います。

浮動小数点数の精度に関する問題については下記ページに記載があります。
http://jp2.php.net/manual/ja/language.types.float.php

1行目部分で$aはfloat型に暗黙的にキャストされるので精度を保てなく
なっているのだと思います。

実装1)精度を維持して浮動小数点計算をおこなうにはPHPの場合は、
bcmul関数などで乗算するのが一番良いのだろうと思います。

BC Math関数
http://jp2.php.net/manual/ja/ref.bc.php

ご指定のような式の結果を出力するのでしたら下記のように小数以下2桁
に揃えて計算するということであれば下記のようにすれば正確にでます。

$a = bcmul( 2, bcmul( 10770, 1.35, 2 ), 2 );
echo $a; // 29079.00
echo ceil($a); // 29079

実装2)整数に揃えてから計算して小数に戻す
Cなんかで浮動小数点乗算するときのセオリーですね。
良く使います。最初に小数点以下の精度がある程度分かっている事が前提ですが

$a= 2 * 10770 * 1.35 * 100;
echo ($a/100); // 29079.00
echo ceil($a/100); // 29079

実装3)一度文字列型にキャストしてから計算する
私の場合結構つかったりしています
私の環境と要件で問題なく動作しているというだけで、
汎用的にはお勧めできませんが…

$a = (string) (2*10770*1.35);
echo $a; // 29079
echo ceil($a); // 29079

これだと処理の順序として、2*10770*1.35の結果を一度文字列にキャスト
して内部値が文字列になってfloatの範囲で丸められます。
その後ceilした時に文字列を再度float型にキャストしますので、計算結果と
表示文字列の整合性がとれるということですが…
かなり強引なやり方なのは分かっているのですが簡便なのでつい利用してしまいます。
これだとこのような問題があるなどのご指摘はぜひ頂きたいです。

□■◇ Masanori Nakashima
■□■ MDS co.,Ltd.
□■□ mail : m_nakashima@xxxxx
■□■ URL : http://www.md-systems.net/
□■◇ オープンソースMDS Tools開発チーム
■□■ URL : http://www.mds-tools.com/
□■□ Tel : 03-5950-0525
■□■ Fax : 03-5950-0526
□■□ Zip : 170-0013
■□■ 311, 25 Sankyo-Blg 1-48-10 Toshimaku Tokyo Jp

_______________________________________________
PHP-users mailing list PHP-users@xxxxx
http://ml.php.gr.jp/mailman/listinfo/php-users
PHP初心者のためのページ - 質問する前にはこちらをお読みください
http://oldwww.php.gr.jp/php/novice.php3


投稿者 xml-rpc : 2010年9月 6日 17:47
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/98124
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。