浮動小数点の乗算と評価の問題

この問題は、コードで最もよく表現されます。

$var1 = 286.46;//user input data
$var2 = 3646;//user input data
$var3 = 25000;//minumum amount allowed
$var4 = ($var1 * 100) - $var2;//= 250000
if ($var4 < $var3) {//if 250000 < 250000
    print 'This returns!';
}

var_dump($var4) outputs: float(25000) and when cast to int, outputs: int(24999) - and thereby lies the problem.

私は本当にそれについて何をすべきかわからない。この問題は100倍で起こりますが、これを回避するためのトリックはありませんが(* 10 * 10など)、この問題に対する「本当の」解決策があるかどうかを知りたいと思います。

ありがとう:)

5
追加された 著者 Michael Borgwardt,

5 答え

これは恐ろしいハックな解決策であり、私はそれを少し嫌っていますが、これは期待される動作を与えます:

<?php

  $var1 = 286.46;//user input data
  $var2 = 3646;//user input data
  $var3 = 25000;//minumum amount allowed
  $var4 = ($var1 * 100) - $var2;//= 250000
  if ((string) $var4 < (string) $var3) {//if 250000 < 250000
      print 'This returns!';
  }

それらを文字列にキャストし、比較のためにint/floatに変換し直します。私はそれが好きではありませんが、それは動作します。

PHPでの正確な浮動小数点数学のためには、実際に BC Math が必要です。

1
追加された

float numberをintとして使用するときは、常にceil(または、あなたが望むものに基づいてフロア)を使用することをお勧めします。 あなたの場合、比較の前にceil($ var4)を試してください!

1
追加された

浮動小数点値の比較に bccomp を使用することはできますが、 PHPコアにない関数です。

そうでなければ、私はこの機能を見つけましたが、ここでテストできませんでしたそれが動作するかどうかを確認する

function Comp($Num1,$Num2,$Scale=null) {
 //check if they're valid positive numbers, extract the whole numbers and decimals
  if(!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num1,$Tmp1)||
     !preg_match("/^\+?(\d+)(\.\d+)?$/",$Num2,$Tmp2)) return('0');

 //remove leading zeroes from whole numbers
  $Num1=ltrim($Tmp1[1],'0');
  $Num2=ltrim($Tmp2[1],'0');

 //first, we can just check the lengths of the numbers, this can help save processing time
 //if $Num1 is longer than $Num2, return 1.. vice versa with the next step.
  if(strlen($Num1)>strlen($Num2)) return(1);
  else {
    if(strlen($Num1)(int)$Num2{$i}) return(1);
        else
          if((int)$Num1{$i}<(int)$Num2{$i}) return(-1);
      }

     //if the two numbers have no difference (they're the same).. return 0
      return(0);
    }
  }
}
0
追加された

浮動小数点数は時々浮動小数点数を表現することができません。

intにキャストする代わりに、数値を整数値に丸めてintにキャストすることができます。 (おそらく、不要なキャストは可能ですが、PHPは内部的にどのように起こるかについてはっきりしませんし、現在の状況を知っていても将来的にはそうでないかもしれません。

0
追加された

問題は、浮動小数点は単にいくつかの数字を表すことができないということです。 PHPには小数点(または他の固定小数点)型がないので、基本的にはこれらの問題を回避するだけです。

あなたの例の最初の数字を$ var1 = 286.46 とすると、ユーザーが入力した直後にそれをセントに直接変換することができます(例えば、ポイントをストリッピングして整数として読むなど)整数計算を使用してすべてを計算します。

これは一般的な解決策ではありません。私は疑問があります(いくつかのPHP拡張機能が提供する任意の精度の数値を使用するのには不足していますが、私にはそれが残念です。

0
追加された
PHP - 日本のコミュニティ [ja]
PHP - 日本のコミュニティ [ja]
4 参加者の

このグループではPHPについて話します。 パートナー:kotaeta.com