【问题标题】:php integer and float comparison mismatchphp整数和浮点比较不匹配
【发布时间】:2017-09-22 19:37:37
【问题描述】:

我有以下代码

$amount1 = 7299;
$amount2 = 72.9875;

$amount2_in_cents = round($amount2, 2) * 100;

if ($amount1 != $amount2_in_cents) {
    echo "Amount $amount1 != $amount2_in_cents\n";

    var_dump($amount1);
    var_dump($amount2_in_cents);    

} else {
    echo "Amounts matched";
}

这是输出

Amount 7299 != 7299
int(7299)
float(7299)

现在我意识到 float 和 int 是不同的,但考虑到舍入,我希望这两个值匹配。我已经通过强制转换为 int 来解决它。

所以我的问题是为什么这个比较没有像我预期的那样起作用(两个值都匹配)?

【问题讨论】:

  • 因为经典的浮点舍入问题。您通过强制转换为 int 解决了它,因为这确保了 7299 的精确值。

标签: php


【解决方案1】:

注意PHP Manual 中的大红色警告

在比较浮点数时不要期望任何东西。舍入的结果,即使精度为 0,仍然是浮点数。在您的特定情况下,结果恰好比预期的要大一些,因此转换为 int 会导致相等,但对于其他数字,它也可能会比预期的要小一些并且转换为 int 不会四舍五入它,但截断它,所以你不能使用强制转换作为解决方法。 (请注意,比您更好的解决方案是强制转换为字符串 :),但仍然是一个糟糕的选择。)

如果您需要处理大量资金,请始终使用BC Math extension

对于 BC Math 的四舍五入,您可以使用以下技术:

$x = '211.9452';
$x = bcadd($x, '0.005', 2);

祝你好运,
阿林

【讨论】:

  • +1 用于 BC Math 的简单舍入解决方案。这正是我所需要的。
【解决方案2】:

使用

round()

$float_val = 4.5;
$float_val = round($float_val);

现在比较

【讨论】:

    【解决方案3】:

    例如一个糟糕的案例:我们想在循环中检查我们的评分是否大于或等于 3.3(满分 5)。 (这都是显示“缺陷”的奇怪示例)

    $a="3.3";
    for($i=0; $i<5 ; $i=$i+0.15){
        echo "\nTesting if $i>=$a\n";
        var_dump($i,$a);
        if($i>=$a){ 
            echo "$i>=$a is TRUE\n";
        }else{
            echo "$i>=$a is FALSE\n";
    
        }
    }
    

    现在输出将是这个:

    Testing if 0>=3.3
    int(0)
    string(3) "3.3"
    0>=3.3 is FALSE
    
    Testing if 0.15>=3.3
    float(0.15)
    string(3) "3.3"
    0.15>=3.3 is FALSE
    
    Testing if 0.3>=3.3
    float(0.3)
    string(3) "3.3"
    0.3>=3.3 is FALSE
    
    Testing if 0.45>=3.3
    float(0.45)
    string(3) "3.3"
    0.45>=3.3 is FALSE
    
    Testing if 0.6>=3.3
    float(0.6)
    string(3) "3.3"
    0.6>=3.3 is FALSE
    
    Testing if 0.75>=3.3
    float(0.75)
    string(3) "3.3"
    0.75>=3.3 is FALSE
    
    Testing if 0.9>=3.3
    float(0.9)
    string(3) "3.3"
    0.9>=3.3 is FALSE
    
    Testing if 1.05>=3.3
    float(1.05)
    string(3) "3.3"
    1.05>=3.3 is FALSE
    
    Testing if 1.2>=3.3
    float(1.2)
    string(3) "3.3"
    1.2>=3.3 is FALSE
    
    Testing if 1.35>=3.3
    float(1.35)
    string(3) "3.3"
    1.35>=3.3 is FALSE
    
    Testing if 1.5>=3.3
    float(1.5)
    string(3) "3.3"
    1.5>=3.3 is FALSE
    
    Testing if 1.65>=3.3
    float(1.65)
    string(3) "3.3"
    1.65>=3.3 is FALSE
    
    Testing if 1.8>=3.3
    float(1.8)
    string(3) "3.3"
    1.8>=3.3 is FALSE
    
    Testing if 1.95>=3.3
    float(1.95)
    string(3) "3.3"
    1.95>=3.3 is FALSE
    
    Testing if 2.1>=3.3
    float(2.1)
    string(3) "3.3"
    2.1>=3.3 is FALSE
    
    Testing if 2.25>=3.3
    float(2.25)
    string(3) "3.3"
    2.25>=3.3 is FALSE
    
    Testing if 2.4>=3.3
    float(2.4)
    string(3) "3.3"
    2.4>=3.3 is FALSE
    
    Testing if 2.55>=3.3
    float(2.55)
    string(3) "3.3"
    2.55>=3.3 is FALSE
    
    Testing if 2.7>=3.3
    float(2.7)
    string(3) "3.3"
    2.7>=3.3 is FALSE
    
    Testing if 2.85>=3.3
    float(2.85)
    string(3) "3.3"
    2.85>=3.3 is FALSE
    
    Testing if 3>=3.3
    float(3)
    string(3) "3.3"
    3>=3.3 is FALSE
    
    Testing if 3.15>=3.3
    float(3.15)
    string(3) "3.3"
    3.15>=3.3 is FALSE
    
    Testing if 3.3>=3.3
    float(3.3)
    string(3) "3.3"
    3.3>=3.3 is FALSE
    
    Testing if 3.45>=3.3
    float(3.45)
    string(3) "3.3"
    3.45>=3.3 is TRUE
    
    Testing if 3.6>=3.3
    float(3.6)
    string(3) "3.3"
    3.6>=3.3 is TRUE
    
    Testing if 3.75>=3.3
    float(3.75)
    string(3) "3.3"
    3.75>=3.3 is TRUE
    
    Testing if 3.9>=3.3
    float(3.9)
    string(3) "3.3"
    3.9>=3.3 is TRUE
    
    Testing if 4.05>=3.3
    float(4.05)
    string(3) "3.3"
    4.05>=3.3 is TRUE
    
    Testing if 4.2>=3.3
    float(4.2)
    string(3) "3.3"
    4.2>=3.3 is TRUE
    
    Testing if 4.35>=3.3
    float(4.35)
    string(3) "3.3"
    4.35>=3.3 is TRUE
    
    Testing if 4.5>=3.3
    float(4.5)
    string(3) "3.3"
    4.5>=3.3 is TRUE
    
    Testing if 4.65>=3.3
    float(4.65)
    string(3) "3.3"
    4.65>=3.3 is TRUE
    
    Testing if 4.8>=3.3
    float(4.8)
    string(3) "3.3"
    4.8>=3.3 is TRUE
    
    Testing if 4.95>=3.3
    float(4.95)
    string(3) "3.3"
    4.95>=3.3 is TRUE
    

    还有令人讨厌的部分:

     Testing if 3.3>=3.3
        float(3.3)
        string(3) "3.3"
        3.3>=3.3 is FALSE
    

    3.3 大于或等于 3.3 但 php 的东西不是!没有意义吧

    现在,如果您在代码前加上 ini_set('precision', 18);,您可以看到评估实际上是:

    Testing if 3.29999999999999893>=3.3
    float(3.29999999999999893)
    string(3) "3.3"
    3.29999999999999893>=3.3 is FALSE
    

    所以 $i=$i+=0.15 隐式地将 $i 转换为浮点数,这将导致此问题。

    对于这种情况,$i+=0.15 应更改为 $i=number_format($i+=0.15, 2)

    【讨论】:

      猜你喜欢
      • 2015-01-20
      • 2011-04-19
      • 1970-01-01
      • 2016-05-24
      • 2016-02-08
      • 1970-01-01
      相关资源
      最近更新 更多