>  기사  >  백엔드 개발  >  PHP 부동 소수점 비교 방법

PHP 부동 소수점 비교 방법

WBOY
WBOY원래의
2016-07-30 13:30:02920검색

부동 소수점 연산 정확도 문제

먼저 예를 살펴보세요:

<code><span><span><?php</span><span>$a</span> = <span>0.1</span>;
<span>$b</span> = <span>0.9</span>;
<span>$c</span> = <span>1</span>;

var_dump((<span>$a</span>+<span>$b</span>)==<span>$c</span>);
var_dump((<span>$c</span>-<span>$b</span>)==<span>$a</span>);
<span>?></span></span></code>

$a $b== $c는 true를 반환하고, 맞음
$c-$b==$a는 거짓,오류

왜 이런 일이 발생하나요?

연산 후 정밀도가 20자리일 때 실제 반환되는 내용은 다음과 같습니다.

<code><span><span><?php</span><span>$a</span> = <span>0.1</span>;
<span>$b</span> = <span>0.9</span>;
<span>$c</span> = <span>1</span>;

printf(<span>"%.20f"</span>, <span>$a</span>+<span>$b</span>); <span>// 1.00000000000000000000</span>
printf(<span>"%.20f"</span>, <span>$c</span>-<span>$b</span>); <span>// 0.09999999999999997780</span><span>?></span></span></code>

$c-$b는 0.09999999999999997780이므로 0.1과 비교하면 false이 문제가 발생합니다. 부동 소수점 숫자 계산에는 정밀도가 포함되기 때문에 부동 소수점 숫자를 이진수로 변환하면 정밀도가 손실될 수 있습니다.


부동소수점 변환 방식

정수 부분은 2로 나눈 나머지 방식을 채택합니다

소수 부분은 2를 곱하여 반올림됩니다.


예: 숫자 8.5를 이진수로 변환합니다.

정수 부분은 8
8/2=4 8%2=0 4/2=2 4%2=0
2/2=1 2%2=0
1은 2보다 작으므로 계산할 필요가 없습니다. 정수 8의 이진 표현은
1000

소수 부분은 0.5

입니다. 0.5x2 = 1.0 반올림 후 소수 부분이 0이므로 더 이상 계산할 필요가 없습니다
십진수 0.5의 이진법은 0.1입니다. 0.9x2=1.8
0.8x2=1.6
0.6x2=1.2

0.2x2=0.4

0.4x2=0.8 0.8x2=1.6 .... 그러면 루프가 계속됩니다. 차단 정확도가 N이면 N 이후의 숫자는 반올림되어 정확도가 손실됩니다. 위의 예에서는 이진수로 변환할 때 정밀도 0.9가 손실되어 비교 중에 오류가 발생합니다.

따라서 부동 소수점 숫자가 마지막 자리까지 정확하다고 절대 신뢰하지 말고, 두 부동 소수점 숫자가 같은지 비교하지 마세요.



부동소수점수를 정확하게 비교하는 방법

1. 라운드 방식으로 처리한 후 비교
예:


2. 고정밀 계산 방법을 사용합니다

먼저 계산을 수행할 때 정확도가 떨어지지 않도록 고정밀 계산 방법을 사용하십시오.


고정밀 연산 방법은 다음과 같습니다.

bcadd는 두 개의 고정밀 숫자를 추가합니다

bccomp는 두 개의 고정밀 숫자를 비교하고 -1,0,1을 반환합니다.

bcdiv는 두 개의 고정밀도 숫자를 나눕니다

bcmod는 고정밀 수치 나머지를 찾습니다
bcmul 두 개의 고정밀 숫자 곱하기

bcpow는 고정밀 숫자의 힘을 찾습니다
<code><span><span><?php</span><span>$a</span> = <span>0.1</span>;
<span>$b</span> = <span>0.9</span>;
<span>$c</span> = <span>1</span>;

var_dump((<span>$c</span>-<span>$b</span>)==<span>$a</span>);                   <span>// false</span>
var_dump(round((<span>$c</span>-<span>$b</span>),<span>1</span>)==round(<span>$a</span>,<span>1</span>)); <span>// true</span><span>?></span></span></code>
bcpowmod는 고정밀 수치 거듭제곱과 계수를 찾습니다

bcscale은 Linux bc
의 "scale="과 동일한 기본 소수점 수를 구성합니다. bcsqrt는 고정밀 숫자의 제곱근을 찾습니다

bcsub 두 개의 고정밀 숫자 빼기


예:




저작권 표시: 이 기사는 블로거의 원본 기사이므로 블로거의 허가 없이 복제할 수 없습니다. 허가.


위 내용은 PHP 부동소수점 숫자 비교 방법을 내용적인 측면까지 포함하여 소개하고 있는데, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되었으면 좋겠습니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:PHP의 객체지향다음 기사:PHP의 객체지향