php integer and float comparison mismatch

前端 未结 3 576
后悔当初
后悔当初 2020-11-29 13:49

I have the following code

$amount1 = 7299;
$amount2 = 72.9875;

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

if ($amount1 != $amount2_in_cents) {
    echo          


        
相关标签:
3条回答
  • 2020-11-29 13:56

    Notice the big red warning in the PHP Manual!

    Never expect anything when comparing floats. The result of round, even if the precision is 0, is still a float. In your particular case it happened that the result was a little bigger than expected, so casting to int resulted in equality, but for other numbers it might as well happen for it to be a little smaller than expected and casting to int won't round it, but truncate it, so you can't use casting as a workaround. (As a note, a better solution than yours would be casting to string :), but still a lousy option.)

    If you need to work with amounts of money always use the BC Math extension.

    For rounding with BC Math you can use this technique:

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

    Good luck,
    Alin

    0 讨论(0)
  • 2020-11-29 13:56

    Use

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

    now Compare

    0 讨论(0)
  • 2020-11-29 13:56

    For example a nasty case: We want to check if our ratting is greater or equal than 3.3 out of 5 while in a loop. ( This is all weird example to show a "flaw")

    $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";
    
        }
    }
    

    Now the output will be this one:

    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
    

    And the nasty part:

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

    3.3 is greater or equal than 3.3 but php things not! Makes no sense right

    Now if you put a ini_set('precision', 18); before the code you can see that the evaluation actually was:

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

    So the $i=$i+=0.15 implicitly converts the $i to a float, which will cause this issue.

    For this case the $i+=0.15 should be changed to $i=number_format($i+=0.15, 2)

    0 讨论(0)
提交回复
热议问题