2011-03-08 4 views
1

다음 코드PHP는 정수 및 부동 비교 불일치

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

이이 나는 수레와 INT는 다르다는 것을 깨닫게 이제 출력

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

하지만 난 것 반올림 부여 두 값이 일치 할 것으로 예상했습니다. 그리고 int로 캐스팅하여 해결했습니다.

내 질문에 왜이 비교가 작동하지 않을 것으로 예상 했습니까 (두 값 모두 일치)?

+1

고전적인 부동 소수점 올림 문제로 인해. '7299'의 정확한 값을 보장하기 때문에 int로 형변환하여 해결했습니다. – BoltClock

답변

20

큰 빨간색 경고PHP Manual에 있습니다.

수레를 비교할 때 아무 것도 기대하지 마십시오. 라운드의 결과는 정밀도가 0 인 경우에도 여전히 부동입니다. 특정 경우에는 결과가 예상보다 조금 더 커졌기 때문에 int로 캐스팅하면 평등하게되지만 다른 숫자의 경우 예상보다 조금 작아서 int로 캐스팅하지 않을 수도 있습니다 그것을 자르지 만 자르므로 캐스팅을 사용할 수 없습니다. (참고로, 당신보다 나은 해결책은 string으로 캐스팅 될 것입니다 :) 그러나 여전히 부실한 옵션입니다.

금액을 항상 사용해야하는 경우 BC Math extension을 사용하십시오. 이 기술을 사용할 수 있습니다 BC 수학 라운딩을 위해

:

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

행운을 빕니다,
알린

+0

+1 BC 금액의 계산을위한 BC 수학. – wimvds

+1

빅 레드 경고 부분을 건너 뛰도록 나를 신뢰하십시오. 감사합니다. – bumperbox

+0

+1 BC Math를 사용한 간단한 반올림 솔루션입니다. 이것은 내가 필요한 것입니다. – toxalot

4

사용

round() 

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

이제 예를 들어 A에 대한

1

비교 더러운 경우 : 우리는 밧줄이 5 중 3.3보다 크거나 같은지 확인하고 싶습니다.

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은

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

    } 
} 

이제 출력이 하나가 될 것입니다 (이것은 "결함"을 표시하는 모든 이상한 예입니다) 3.3보다 크거나 같지만 PHP는 아닙니다!

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

을 따라서는 $ I = $ i가 0.15가 암시 적으로 $를 = 변환 + : 당신은 당신이 평가가 사실이라고 볼 수있는 코드 전에 ini_set('precision', 18);을 넣으면 지금은 아무 의미를 잘

하지 않습니다 플로트, 나는이 문제가 발생할 것입니다.

이 경우 $ i + = 0.15$ i = number_format ($ i + = 0)으로 변경해야합니다.15, 2)