【问题标题】:PHP Simple Math Results in Unexpected ResultPHP 简单数学导致意外结果
【发布时间】:2014-09-04 15:01:41
【问题描述】:

我在一个 PHP 程序中有两个变量用于帐单,$charges 和 $payments。

$charges 是在任何付款之前到期的总金额。 $payments 是收到的总金额。

我这样计算应付余额:

$balance_due = $charges-$payments;

简单,除了我得到以下结果:

$balance_due has -9.0949470177293E-13 for a value (expecting 0).

$charges 和 $payments 的值都是 5511.53。

当我 var_dump($charges)var_dump($payments) 他们都显示:float(5511.53)

此代码(和 === ):

if($charges == $payments){
  error_log('they are the same');
}else{
  error_log('they are not the same');
}

两者都为假。

如果我硬编码:$charges = $payments = 5511.53;然后按预期运行 $balance_due = 0。

我很困惑。我错过了什么?

编辑注释

我能够使用由 Nitrogen 在 BC Math Functions 页面上找到的用户贡献功能,建议我查看该功能以提出以下解决方案:

if(Comp($charges, $payments)===0){
    $balance_due = 0;
}else{
    $balance_due = ( $charges - $payments );
}


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)<strlen($Num2)) return(-1);

    // if the two numbers are of equal length, we check digit-by-digit
    else {

      // remove ending zeroes from decimals and remove point
      $Dec1=isset($Tmp1[2])?rtrim(substr($Tmp1[2],1),'0'):'';
      $Dec2=isset($Tmp2[2])?rtrim(substr($Tmp2[2],1),'0'):'';

      // if the user defined $Scale, then make sure we use that only
      if($Scale!=null) {
        $Dec1=substr($Dec1,0,$Scale);
        $Dec2=substr($Dec2,0,$Scale);
      }

      // calculate the longest length of decimals
      $DLen=max(strlen($Dec1),strlen($Dec2));

      // append the padded decimals onto the end of the whole numbers
      $Num1.=str_pad($Dec1,$DLen,'0');
      $Num2.=str_pad($Dec2,$DLen,'0');

      // check digit-by-digit, if they have a difference, return 1 or -1 (greater/lower than)
      for($i=0;$i<strlen($Num1);$i++) {
        if((int)$Num1{$i}>(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);
    }
  }
}

该解决方案对我有用。下面由 imtheman 提供的答案也有效,而且似乎更有效,所以我将使用那个答案。 有什么理由不使用其中的一种吗?

【问题讨论】:

  • 欢迎使用浮点数。 php.net/manual/en/…
  • 你问如何解决这个问题?或者为什么会这样?
  • 欢迎来到浮点数的美妙世界,这里的准确性是不可能的,一切都是近似的。您基本上得到“0” - 您的值是 10 到负 13,即0.0000000000000909494....。出于所有意图和目的,它为零。
  • BC Math Functions 也应该是值得研究的东西。

标签: php


【解决方案1】:

当我遇到这个问题时,我解决这个问题的方法是使用 php 的number_format()。来自php documentation

string number_format(float $number [, int $decimals = 0 ])

所以我会这样做:

$balance_due = number_format($charges-$payments, 2);

这应该可以解决您的问题。

注意:number_format() 将返回一个字符串,因此要比较它,您必须使用==(不是===)或在比较之前将其转换回(float)

【讨论】:

    猜你喜欢
    • 2021-04-24
    • 1970-01-01
    • 2014-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多