質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

2回答

5208閲覧

税率対応で誤差が出てしまう

whimyama

総合スコア9

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2019/09/04 05:58

編集2019/09/04 06:23

税率対応で誤差が出ます。

PHPバージョンは「PHP 5.3.18」です。

例えば、価格=1000で税率10%の場合、下記処理だと「1101」となってしまいます。
まるめ誤差の影響でしょうか??対策などありますでしょうか?

// 税率 $taxRate=0.080; //$taxRate=0.100; // 端数区分 $taxHasu="1"; //$taxHasu="2"; //$taxHasu="3"; // 価格 $price=1000; // 計算誤差を考慮 $calctaxRate = (1 + $taxRate) * 100; /******** 税抜処理 **************************/ // 切捨て if ( $taxHasu == "1" ) { $outPrice=ceil( ($price/$calctaxRate) * 100); // 四捨五入 } else if ( $taxHasu == "2" ) { $outPrice=round( ($price/$calctaxRate) * 100); // 切上げ } else if ( $taxHasu == "3" ) { $outPrice=floor( ($price/$calctaxRate) * 100); } /******** 税込処理 **************************/ // 切捨て if ( $taxHasu == "1" ) { $inPrice=floor(($price*$calctaxRate)/100); // 四捨五入 } else if ( $taxHasu == "2" ) { $inPrice=round(($price*$calctaxRate)/100); // 切上げ } else { $inPrice=ceil(($price*$calctaxRate)/100); }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/09/04 06:00

そのまま動作させて動くコードで質問してください。
m.ts10806

2019/09/04 06:06

コピペで現象再現するコードをご提示ください。 また、PHPのバージョンも質問本文に追記してください
m.ts10806

2019/09/04 06:24

1100が出力されます。
whimyama

2019/09/04 06:24

失礼しました。ご指摘部分を追記しました。
Y.H.

2019/09/04 06:33

910と1100になります。 質問者さんのところでは後者が1101と表示されるということでしょうか? echo $outPrice . PHP_EOL; echo $inPrice . PHP_EOL; 910 1100 $ php -v PHP 7.2.19-0ubuntu0.18.04.2 (cli) (built: Aug 12 2019 19:34:28) ( NTS )
whimyama

2019/09/04 06:36

ご確認ありがとうございます。その通りです。
Y.H.

2019/09/04 06:56

$calctaxRate に直接 110 を代入して計算するとどうなりますか?
退会済みユーザー

退会済みユーザー

2019/09/04 08:24 編集

明示的に切り捨てるならflor()、切り上げるならceil()ってのがあるけどね。浮動小数点を使う以上誤差は出ちゃうから、都度検算して修正する気配りをコーディングするしかない気もする。消費税の計算って、四捨五入なんてことはせず、全てにおいて切り捨て、あるいは全てにおいて切り上げ、っていうのが店舗や事業単位のルールだった気がするけど、違うか?
whimyama

2019/09/04 08:27

確かにその通りですね。統一されているはずです。 都度潰していくしかなさそうですね。。
guest

回答2

0

「切り上げ」の時に発生してるんですよね?

まるめ誤差の影響

ですね。

実は、ceil(0.1 * 100) + 100ceil((0.1 + 1) * 100)

を頭で計算すると両方とも110になりますが、phpで計算すると結果が一致しないです。

php

1var_dump(ceil(0.1 * 100) + 100, ceil((0.1 + 1) * 100));

の結果は

float(110) float(111)

こうなります。。。※詳しくはこのあたりを読んでくださいphp:浮動小数点数

これが税込計算で切り上げた時に発生する「1円の誤差」の原因だと思います。

で、そもそもなのですが。

php

1 // 計算誤差を考慮 2 $calctaxRate = (1 + $taxRate) * 100;

この部分、せっかくここで誤差を考慮するのであれば、
「税率が少数値である」という要素そのものを排除すべきなので、intvalなどの型変換で、明確に整数値にしたほうがいいのでは、と思いました。

php

1 // 計算誤差を考慮 2 $calctaxRate = intval((1 + $taxRate) * 100);

今のままだと、$calctaxRateは少数値のままなので、
「税率側の少数値による誤差」が発生するリスクは含まれたままです。


追記です。

私が使った動作確認のコードを載せてみますので、お手元で実行してみてください。
ちなみに動作確認は、5.3.18の環境はなかったので、5.3.3及び7.2.17で確認しました。両環境で同じ結果になります。

php

1 // 税率 2 $taxRate=0.1; 3 4 // 価格 5 $price=1000; 6 7echo '<pre>'; 8 echo 'price = '.$price.PHP_EOL; 9 echo '--------------------------'.PHP_EOL; 10 11 //少数値のまま計算 12 echo '■floatval Tax'.PHP_EOL; 13 14 $calctaxRate = (1 + $taxRate) * 100; 15 echo 'tax = '; 16 var_dump($calctaxRate); 17 18 //こっちは1101になる 19 echo 'ceil((price * tax) / 100) = '; 20 var_dump(ceil(($price*$calctaxRate)/100)); 21 22 echo '--------------------------'.PHP_EOL; 23 24 //整数値に変換して計算 25 //echo '■intval Tax'.PHP_EOL; 26 //$calctaxRate = intval((1 + $taxRate) * 100); 27 echo '■round Tax'.PHP_EOL; 28 $calctaxRate = round((1 + $taxRate) * 100); 29 30 echo 'tax = '; 31 var_dump($calctaxRate); 32 33 //こっちは1100になる 34 echo 'ceil((price * tax) / 100) = '; 35 var_dump(ceil(($price*$calctaxRate)/100)); 36 37echo '</pre>'; 38

あと、ツッコミ忘れておりましたが、質問に提示されているコードの「税抜処理」の方、「切り上げ」と「切り捨て」で使っている関数が逆ですヨ^^;


maisumakunさんよりご指摘をうけましたので、訂正追記を。

整数値変換にintvalを使うと、税率が「13%」になるかもしれない近い未来(なったら困りますね・・)に、誤差の原因となってしまうので、roundでの整数値変換の方が正確でした。

※動作確認コードを修正しました。

投稿2019/09/04 07:18

編集2019/09/05 08:13
mix-peach

総合スコア1910

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

whimyama

2019/09/04 08:01

丁寧なご回答ありがとうございました。 試しにintvalで囲ってみたのですが、状況変わらずでした。
mix-peach

2019/09/04 08:48

コード載せてみたので、お手元の環境で動かして確認していただけますか?
maisumakun

2019/09/04 08:55

intvalの場合切り捨てとなるので、本来の値よりわずかに小さい場合に1切り捨てられてしまいます。roundでいちばん近い整数に持っていったほうがいいでしょう。
mix-peach

2019/09/05 08:15

>maisumakun さん ご指摘ありがとうございます。 確かに今後に税率があがることを想定せずに提案してしまいました・・! roundの方が正確なので、そのように回答を訂正追記させていただきました。
guest

0

見た感じ税抜から税込への変換で誤差がでるような箇所はなさそうですけど

PHP

1$zeinuki=1000; 2$zeiritu=0.1; 3$rate=(1+$zeiritu)*100; 4$zeikomi=$zeinuki*$rate/100; 5 6print "税込み:{$zeikomi}<br>";

投稿2019/09/04 06:15

yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

whimyama

2019/09/04 08:02

ご回答ありがとうございます。自身でももう少し詳しく調査してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問