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

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

ただいまの
回答率

89.98%

PHPで小数点第3位以下を切り捨てたい。

解決済

回答 7

投稿

  • 評価
  • クリップ 0
  • VIEW 17K+

coffee

score 150

やりたい事は下記のような事です。

1.450 -> 1.45
1.455 -> 1.45
1.459 -> 1.45

この様に小数点第3位以下を四捨五入等せずに切り捨てたいです。

そこで、round関数を使って下記のように書いてみましたが、
勝手に小数点第3位が四捨五入されました。。

round(1.459, 2, PHP_ROUND_HALF_DOWN);
-> 1.46

マニュアルを見ると、第三引数の mode で PHP_ROUND_HALF_DOWN を指定すれば、
うまくいくと思ったのですが、、何かいい方法あれば教えて下さい。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

+3

回答は既に出ていますが、roundはそもそも広義の「四捨五入」の関数です。
表現がめんどくさいので整数に丸める前提で説明します。
丸める部分がちょうど 0.5 (HALF)の時に、狭義の四捨五入だと切り上げますが、そうじゃない方法が他に3通りあると言うことです。
その1つである PHP_ROUND_HALF_DOWN は、0.5よりちょっとでも大きいと切り上げるが、0.5以下ときは切り捨てるということです。Wikipediaの「端数処理」の項目では、「五捨五超入」と書かれています。

正確には、PHP_ROUND_HALF_UP以外は四捨五入じゃ無いので、関数の説明に四捨五入と書けず、「まるめ」と表現したのでしょう。しかし、切り捨て、切り上げも「まるめ」の一種なので、その点でおかしくなっています。

追記:
floor()やceil()に何故桁数指定機能が無いのかを考えてみると、単純に100をかけて切り捨てて100で割る方法だと、値によっては、10進数に直してから第3位を切り捨てるのと比べると差が出るケースもあったりするので、避けてるのかなと言う気がします。いったん10進数に変換してから(つまり文字列に変換してから)処理した方が正確だと思います。

実際、試してみると差が出るケースがありました。
PHP 5.3.3 (cli) (built: Oct 30 2014 20:12:53)
<?php
$a=10+0.001*40;
var_dump($a);                 //=> float(10.04)
var_dump(floor($a*100)/100);  //=> float(10.03)
いったん文字列に直して、小数点以下3桁目以降を削除するという方法がいいようです。
var_dump(floor($a)+substr(sprintf("%5.3f",$a-floor($a)),0,4));
とか。$aが負の場合も考慮すると、正負の場合分けが必要そうです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

$arg = 1.459;
echo (floor($arg * 100)) / 100;
これでどうでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

だいぶ日が経っていますが、私のやり方も参考になればと思います。
私も小数の演算に関しては痛い目に遭いました。。

こんな感じです。sprintfは不要かもですが、適当ですみません。

ceil(sprintf("%.3f", 1.459) + 0.001)*100)/100)-0.01

ceilは「.0なら切り上げない」「.1以上なら切り上げる」性質を持っていますので、
これを利用します。
強制的に+0.001してからceilをかませ、最後に繰り上がった分を強制的に引く(-0.01)わけです。

元が1.459の場合・・・ceil(1.46  *100)/100なので結果は変わらず。最後に-0.01で1.45です。
元が1.455の場合・・・ceil(1.456 *100)/100なので0.006が0.01に繰り上がります。最後に-0.01で1.45です。

何かと不安要素の多いfloorを使うよりも、ceilはハッキリしているので確実な方法だと思っています。

輸出入のWebシステムで実際に動いています。
納品書などに重量や単価、横計など上記の数式を用いて、PHPExcelで紙を出しています。

為替やkg⇔ポンドの変換等で多用していますが、差分が出たことはありません。

解決済とは思いますが、せっかくなのでご参考まで。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

PHPはあまり詳しくないですけど…

四捨五入されてしまうのであれば
"0.05"を引いてみてはいかがでしょう?

round(1.459, 2, PHP_ROUND_HALF_DOWN);
-> 1.46
round(1.459 - 0.05, 2, PHP_ROUND_HALF_DOWN); // round(1.454, 2, PHP_ROUND_HALF_DOWN);
-> 1.45

切り上げ、切り捨て、四捨五入の調整によくあるアルゴリズムです

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

単純な方法ですが、下記のような方法を使えば簡単にできるような気もするのですが・・・・。

<?php
$data = 1.4499999;
if(is_float($data)){
    $tmp = explode(".", $$data);
    $data = $tmp[0].".".substr($tmp[1], 0, 2);
}
var_dump($data);
exit;
?>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/06/12 00:44

    いろいろ考えて追記している間に、文字列を使った回答も出ましたね。
    なるほど、takayukiinaba さんの方法だと、正負の場合分けは要らなそうです。
    と思ったけど、$data = 5; とかだと$tmp[1]で警告が出ますね。やはり場合分けは必要か。
    と思ったけど、$tmp = explode(".", $data.".0"); で回避できます。
    最後は文字列のままなので、数値化のために0を足すのでしょうか。

    キャンセル

  • 2015/06/12 00:52

    otn さん
    突っ込みありがとう御座います。
    確かにそうですね、入力されるデータが実数値という認識でした。

    キャンセル

0

float a = 123.456
int ans = (a * 1000);
flat a = ans;
print( a );

ですかね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

せっかくなので、別のアプローチとして
文字列で切り出すのはどうですか?
小数点第3位以下切り捨てであれば

preg_match("/([0-9]+\.[0-9]{2})/",$val,$tmp);

$result = $tmp[1];

で取れそうな気がします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 89.98%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる