>  기사  >  백엔드 개발  >  PHP의 소수점 정밀도 코드 분석

PHP의 소수점 정밀도 코드 분석

不言
不言원래의
2018-08-04 14:02:411991검색

이 기사의 내용은 PHP의 소수점 정밀도에 대한 내용입니다. 특정 참조 값이 있으므로 도움이 될 수 있습니다.

프로젝트에서 소수점 이하 두 자리까지 반올림할 때 정확도 문제가 발생했습니다.

$num = 0.99;
$num1 = round($num, 2);//0.98999999999999999
$num2 = floatval($num);//0.98999999999999999

현재 해결 방법:

sprintf("%.2f", round($money, 2));//会自动四舍五入
echo substr(sprintf("%.3f",$n), 0, -1);//不四舍五入

테스트 결과:

var_dump(json_encode(round(0.99 ,2)));//0.98999999999999999
var_dump(round(0.99 ,2));//0.99

$f = 0.58;    
var_dump(intval($f * 100));//57

57과 같은 문제에 대해 분석할 수 있습니다.

부동 소수점 숫자 표현( IEEE 754: IEEE 이진 부동 소수점 산술 표준):

길이가 64비트(이중 정밀도)인 부동 소수점 숫자는 1개의 부호 비트(E), 11개의 지수 비트(Q) 및 52개의 가수를 사용합니다. 비트(M)는 (총 64비트)를 나타냅니다.

부호 비트: 가장 높은 비트는 데이터의 부호를 나타내며, 0은 양수, 1은 음수를 나타냅니다.

 지수 비트: 밑이 2인 데이터의 거듭제곱을 나타내며 지수는 오프셋 코드로 표현됩니다.

 가수: 데이터의 소수점 이하 유효 숫자를 나타냅니다.

0.58 이진 표현의 경우 무한한 값입니다. :

 0.58 0.57의 이진 표현은 기본적으로 다음과 같습니다: 0010100011110101110000101000111101011100001010001111

0.57의 이진 표현은 기본적으로 00100011110101110000입니다. 1010 001111010111000010100011110

그리고 이 52비트로만 계산하면 둘의 이진수는 다음과 같습니다.

  0.58 -& gt; 0.5799999999999996

0.57-& gt; 0.569999999999999

따라서 0.58 * 100 결과: 57999999999, 정수로 변환: 57

부동 소수점의 이진수 숫자

:

(0.1 + 0.7) == 0.8//false

floor((0.1+0.7)*10)//7 
//内部结果可能是:7.9999999999
//所以:不可能精确的用有限位数表达某些十进制分数
1/3=3.33333333333
//而3.333333333333333*3,却不是1

그래서 결론:

그러므로 부동 소수점 결과가 마지막 자리까지 정확하다고 절대 신뢰하지 말고 두 부동 소수점 숫자가 같은지 비교하지 마세요. 정말로 더 높은 정밀도가 필요하다면 임의 정밀도 수학 함수나 gmp 함수를 사용해야 합니다

고정밀 함수 사용을 권장합니다:

고정밀 함수

  • bcadd - 임의 정밀도 2개 추가 숫자

  • bccomp — 두 개의 임의 정밀도 숫자 비교

  • bcp — 2개의 임의 정밀도 숫자 나누기

  • bcmod — 임의 정밀도 숫자 모듈로

  • bcmul — 2개의 임의 정밀도 숫자 곱하기

  • bcpow — 모든 정밀 숫자의 힘

  • bcpowmod — 임의의 정밀도 숫자를 다른 정밀도 숫자로 올리고 지정된 계수만큼 줄입니다.

  • bcscale — 모든 bc 수학 함수의 기본 소수 자릿수 설정

  • bcsqrt — 임의 정밀도 숫자의 제곱근

  • bcsub — 2개의 임의 정밀도 숫자 빼기

반올림을 위해 고정밀 함수 사용:

    function getBcRound($number, $precision = 0)
    {
        $precision = ($precision < 0)
                   ? 0
                   : (int) $precision;
        if (strcmp(bcadd($number, &#39;0&#39;, $precision), bcadd($number, &#39;0&#39;, $precision+1)) == 0) {
            return bcadd($number, &#39;0&#39;, $precision);
        }
        if (getBcPresion($number) - $precision > 1) {
            $number = getBcRound($number, $precision + 1);
        }
        $t = &#39;0.&#39; . str_repeat(&#39;0&#39;, $precision) . &#39;5&#39;;
        return $number < 0
               ? bcsub($number, $t, $precision)
               : bcadd($number, $t, $precision);
    }
    
    function getBcPresion($number) {
        $dotPosition = strpos($number, &#39;.&#39;);
        if ($dotPosition === false) {
            return 0;
        }
        return strlen($number) - strpos($number, &#39;.&#39;) - 1;
    }
    
    $money = getBcRound(0.99, 2);

추천 관련 기사:

in AES 암호화 파일의 PHP 분석(코드 포함)

POST 및 PHP 컬의 GET 요청 코드

PHP 중간 핵심 콘텐츠 분석 정보

위 내용은 PHP의 소수점 정밀도 코드 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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