2009-10-22 3 views
13

다른 수학 계산 문제가 다시 발생했습니다.PHP 플로트 계산 2 소수점

$a = 34.56 

$b = 34.55 

$a

$b

$c = $b - $a 

가정으로 내가 -0.01해야하다 일이 무엇인지이 그림을

를 얻기 위해 가장 가까운 0.05를 반올림하고있는이 그림을 얻기 위해 몇 가지 계산을 수행 하지만 나는 $c가 표시됩니다 -0.00988888888888

입니다3210

나는 N umber_format($c, 2)을 사용하려고하지만, 출력은

는 어떻게 $a$b 정확히 2 개 소수, 뒷면에 숨겨진 수 있는지 확인 할 수 있습니다 0.00입니다. 디스플레이를 포맷 할 경우에만 할 수 내 PHP는 지식로 number_format에서

, 값 정말 2 진수,

내가 여기에서 도움을받을 수 있기를 바랍니다. 이것은 정말로 나를 좌절 시켰습니다.

+0

php.ini에서 '정밀도'를 조사하여 PHP 전반의 변경 사항을 광범위하게 검사합니다. 그러나 중요한 숫자 *를 다루고 있음을 알려드립니다. –

답변

34

시도 sprintf("%.2f", $c);

부동 소수점 숫자는 당신이 뒤에 오는 숫자를 얻을 이유는, 그래서 소수가 종료 진수를하지 않을 수 있습니다 종료, 2의 제곱에 따라 IEEE 표기법으로 표시됩니다.

가변 길이 코더가 제안한 바에 따르면 원하는 정밀도를 알고 변경하지 않는 경우 (예 : 돈을 처리 할 때) 고정 소수점 수를 사용하는 것이 좋습니다 (즉, 센트로 숫자 표현).

$a = 3456; 

$b = 3455; 

$c = $b - $a; 

sprintf ("%.2f", $c/100.0); 

이렇게하면 인쇄하기 전에 많은 계산을 수행하면 반올림 오류가 발생하지 않습니다.

+0

답변을 주셔서 감사합니다. 유일한 방법은 출력 형식을 지정하는 것입니다. 문자열을 사용하는 경우를 제외하고는 십진수로 설정할 수 없습니다. – Shiro

+0

그냥 2 자리수로 설정하려면 부동 소수점이 아닌 고정 소수점 숫자를 사용해야합니다. 가변 길이 코더의 대답을 참조하십시오. –

+0

"고정 소수점"숫자가 의미하는 바를 이해하지 못했습니다. 친절히 예제를 제공해 줄 수 있습니까? 고마워요! – Shiro

12

사용 round()는 :

$c = round($b - $a, 2); 

참고 : 당신은 또한 적절하게 반올림 모드를 선택할 수 있습니다.

편집 :

$c = number_format($b - $a, 2); 

$c = sprintf("%.2f", $b - $a); 

대 :
가 좋아 내가 sprintf()number_format()이 아니라고하고있는 것을 얻을하지 않습니다?

+0

아마도 아무것도 아니지만, sprintf()는 C에 익숙한 나 같은 사람들에게 사용하는 것이 훨씬 재미있다.'$ foo = number_format ($ b - $ a, 2)를 저장한다. "사과!"라고 쓰고 대신'$ foo = sprintf ("% .2f apples!", $ b - $ a)'를 쓰면 훨씬 더 우아합니다. –

+0

둥근 암석, 아마도 내가 아는 전부일지도 모르지만, 여전히 배우기. – Newb

2

부동 소수점의 트랩 중 하나에 부딪혔습니다. 정확한 십진수를 항상 나타낼 수는 없습니다. 정확한 십진수 값을 원한다면 정수를 사용한 다음 끝에 원하는 정밀도로 나눈 것이 좋습니다.

예를 들어, 재판매 한 달러 (또는 원하는 통화)로 계산하는 경우 정수 계산으로 실제로 계산할 수 있습니다.

+0

정수 센트가 어떻게 작동하는지 예를 들어 주시겠습니까? 네가 의미하는 바를 얻지 못한다. 의견을 보내 주셔서 감사합니다. – Shiro

+0

"정수 센트"는 $ 24.95를 부동 소수점 24.95가 아니라 정수 2495로 저장해야 함을 의미합니다. $ 10.00은 정수 1000으로 저장됩니다. –

2

bcmath 라이브러리를 사용하여 이러한 모든 문제를 간단하게 회피 할 수 있습니다.

인수를 문자열 또는 숫자 데이터 유형으로 전달하는지 여부를 기억하십시오.

4

기본 계산 :

$a = 34.56; 
$b = 34.55; 
$c = $b - $a; // -0.010000000000005  

작품 (실수 계산을 위해 항상 BC 기능을 사용하여 문제가 모든 C 기반 플랫폼을 위해!)로 예상 :

$a = '34.56'; 
$b = '34.55'; 
$c = bcsub($b, $a, 4); // -0.0100  
+0

자세한 내용은이 단원을 참조하십시오. float/double 데이터 형식보다는 문자열을 사용하여 데이터를 나타냅니다. 그런 다음 BCMath 함수를 사용하여 변수를 계산하십시오. sprintf ('% 1 $ s', bcadd ($ var1, $ var2))를 활용하려면; 데이터베이스 데이터 저장소에도 동일하게 적용됩니다. http://php.net/manual/en/book.bc.php – fyrye

3

I 또한 최근에는 수레로 계산할 때이 문제가 발생했습니다. 예를 들어, 나는 빼고 형식을 지정할 때 값이 -0.00 인 2 개의 부동 소수점을가집니다. 내가 무슨 짓을

$floatOne = 267.58; 
$floatTwo = 267.58; 
$result = number_format($floatOne - floatTwo, 2); 
print $result; //printed a string -0.00 

했다 : 내 솔루션에서

$result = abs($floatOne - $floatTwo);// Made the number positive 
print money_format('%i', $result); // printed the desired precision 0.00 

내가 floatOne이 floatTwo보다 적은 수 없을 것이라는 점을 알고있다. money_format 함수는 시스템에 strfmon 기능이있는 경우에만 정의되며 Windows에서는 그렇지 않습니다.

1

여전히 부동 소수점 빼기가 오류 또는 이상한 값을 초래하는 비슷한 문제가있는 사용자가있는 경우 이 문제에 대해 좀 더 자세히 설명하고 싶습니다. 범인은 부동 소수점 숫자입니다. 다른 운영 체제와 다른 프로그래밍 언어가 다르게 작동 할 수 있습니다.

문제를 설명하기 위해 아래에 간단한 예를 들어 설명합니다.

이것은 PHP와 직접 관련이 없으며 버그가 아닙니다. 그러나 모든 프로그래머는이 문제를 알고 있어야합니다.

이 문제는 20 년 전부터 많은 사람들의 목숨을 앗아갔습니다.

1991 년 2 월 25 일, MIM-104 패트리어트 미사일 배터리의 부동 소수점 계산에서의이 문제는 사우디 아라비아 다란 (Dhahran)에서 들어오는 스커드 미사일을 차단하여 미 육군 제 14 사단 분리 팀의 28 명의 병사가 사망하게했다.

하지만 어떻게됩니까?

이유는 부동 소수점 값이 제한된 정밀도를 나타 내기 때문입니다. 따라서 처리 후에도 의 문자열 표현이 같지 않을 수 있습니다. 또한 은 스크립트에 부동 소수점 값을 쓰고 직접 수학 연산없이 을 인쇄합니다.

그냥 간단한 예 :

$a = '36'; 
$b = '-35.99'; 
echo ($a + $b); 

당신이 바로 0.01를 인쇄하는 기대? 그러나 매우 이상한 답변을 인쇄합니다 0.009999999999998

다른 숫자와 마찬가지로 부동 소수점 숫자 double 또는 float는 0과 1의 문자열로 메모리에 저장됩니다.부동 소수점이 정수와 다른 점은 우리가 0과 1을 어떻게 보는지를 해석 할 때입니다. 그들이 저장되는 방법에 대한 많은 표준이 있습니다. 바로 ....

진수 숫자가 아니라 바이너리로 표현되지 않은 왼쪽에서

부동 소수점 숫자는 일반적으로, 부호 비트, 지수 필드 및 유효 숫자 나 가수 등의 컴퓨터 자료로 포장된다 충분한 공간이 부족하기 때문입니다. 그래서 1/3 정확히 0.3333333 ...이라고 표현할 수 없습니다. 그렇죠? 우리가 0.01을 이진수 부동 소수점 숫자로 표현할 수없는 이유는 동일한 이유 때문입니다. 1/100은 0.00000010100011110101110000 ..... 반복 10100011110101110000입니다.

0.01이 2 진수로 01000111101011100001010으로 단순화되고 시스템 잘림 형식으로 유지되면 십진수로 다시 변환 될 때 0.0099999와 같이 표시됩니다. ... 시스템에 따라 다릅니다 (64 비트 컴퓨터는 32 비트보다 훨씬 더 정밀함을 제공합니다). 운영 체제는이 경우 인쇄 된대로 인쇄할지 또는 사람이 읽을 수있는 방식으로 인쇄 할지를 결정합니다. 그래서, 그것은 기계에 의존하여 어떻게 표현하고 싶어하는가입니다. 그러나 다른 방법으로 언어 수준에서 보호 될 수 있습니다.

결과를 포맷하면 echo number_format (0.009999999999998, 2); 0.01을 인쇄합니다.

이 경우 읽어야하는 방법과 필요한 정밀도를 지정하기 때문입니다.