문제

또 다른 수학 계산 문제가 다시 발생했습니다.

$a = 34.56

$b = 34.55

$a 이 수치를 얻으려면 계산을 수행하십시오

$b 이 그림을 얻으려면 가장 가까운 0.05를 반올림하고 있습니다

무슨 일이 일어나는지

$c = $b - $a

아마도 나는 -0.01이어야하지만 나는 $c Show -0.00988888888888입니다

나는 n을 사용하려고 노력한다umber_format($c, 2), 그러나 출력은 0.00입니다.

어떻게 확인할 수 있습니까? $a 그리고 $b 뒷면에는 정확히 2 개의 소수점이지만 숨겨진 숫자는 없습니다.

내 PHP Knowledge Number_format에서 디스플레이를 형식화 할 수는 있지만 실제로는 2 십수 단위가 아닙니다.

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

도움이 되었습니까?

해결책

노력하다 sprintf("%.2f", $c);

부동 소수점 번호는 2의 전력을 기반으로 IEEE 표기법으로 표시되므로 소수점 숫자를 종료하는 것은 종료 된 이진 번호가 아닐 수 있으므로 후행 숫자를 얻는 이유입니다.

가변 길이 코더가 제안한 바와 같이, 원하는 정밀도를 알고 변화하지 않으면 (예 : 돈을 다룰 때) 고정점 번호를 사용하는 것이 더 나을 수 있습니다.

$a = 3456;

$b = 3455;

$c = $b - $a;

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

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

다른 팁

사용 round():

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

메모: 반올림 모드를 적절하게 선택할 수도 있습니다.

편집하다: 알았어, 나는 무엇을 얻지 못한다 sprintf() 그렇게하고 있습니다 number_format() 그렇지 않다 :

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

vs

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

?

기본 계산 :

$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.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

내 솔루션에서 나는 플로톤이 Floattwo보다 적을 수 없다는 것을 알고 있습니다. 그만큼 Money_format 함수는 시스템에 strfmon 기능이있는 경우에만 정의되며 Windows는 그렇지 않습니다.

당신은 부동 소수점 번호의 함정 중 하나를 만날 수 있습니다. 그들은 항상 정확한 소수점 분수를 나타낼 수는 없습니다. 정확한 소수점 값을 원한다면 정수를 사용한 다음 끝에 원하는 정밀도로 나누는 것이 좋습니다.

예를 들어, 플로트를 대표하는 플로트로 계산을하는 경우 (또는 좋아하는 통화) 실제로 정수 센트에서 계산을 수행 할 수 있습니다.

BCMATH 라이브러리를 사용하여 이러한 모든 문제를 매우 깔끔하게 회피 할 수 있습니다.

문서를 읽고 문자열 또는 숫자 데이터 유형으로 인수를 전달하는지 조심하십시오.

여전히 누군가가 부유 숫자 뺄셈으로 인해 오류 또는 이상한 값이 발생하는 유사한 문제 로이 페이지에 도달하면. 이 문제를 좀 더 자세히 설명하고 싶습니다. 범인은 부동 소수점 번호입니다. 그리고 다른 운영 체제와 다른 버전의 프로그래밍 언어는 다르게 행동 할 수 있습니다.

문제를 설명하기 위해 아래의 간단한 예제로 이유를 설명하겠습니다.

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

이 문제는 20 년 전에 많은 삶을 사로 잡았습니다.

1991 년 2 월 25 일, MIM-104 애국자 미사일 배터리에서 부동 수 계산 의이 문제는 사우디 아라비아의 다크란에서 들어오는 스커드 미사일을 가로 채어 미 육군의 14 쿼터 마스터 분리에서 28 명의 병사들의 사망에 기여하는 것을 방지하지 못했습니다.

하지만 왜 그런 일이 발생합니까?

그 이유는 부동 소수점 값이 제한된 정밀도를 나타 내기 때문입니다. 따라서 처리 후 값이 동일한 문자열 표현을 가질 수 있습니다. 또한 스크립트에 부동 소수점 값을 작성하고 수학 연산없이 직접 인쇄하는 것이 포함됩니다.

간단한 예 :

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

0.01을 인쇄 할 것으로 예상 하시겠습니까? 그러나 그것은 0.009999999999998과 같은 매우 이상한 대답을 인쇄 할 것입니다.

다른 숫자와 마찬가지로 부동 소수점 번호는 두 배나 플로트가 메모리에 0과 1의 문자열로 저장됩니다. 플로팅 포인트가 정수와 다른 방법은 우리가보고 싶을 때 0과 1을 해석하는 방식에 있습니다. 표준이 저장되는 방법이 많이 있습니다.

부동 소수점 숫자는 일반적으로 왼쪽에서 오른쪽으로 부호 비트, 지수 필드 및 중요도 또는 Mantissa로 컴퓨터 데이텀에 포장됩니다 ....

충분한 공간이 없기 때문에 소수점 숫자는 바이너리로 잘 표현되지 않습니다. 그래서, uou는 0.3333333 ...에 정확히 1/3을 정확하게 표현할 수 없습니다. 이진 플로트 번호가 같은 이유로 0.01을 표현할 수없는 이유는 같은 이유가 있습니다. 1/100은 0.000011010001111011110000입니다 ..... 반복 10100011110101110000.

바이너리에서 0.01이 단순화되고 시스템 트리치 된 형태의 010001111010111001001010으로 보관하면, 소수점으로 다시 번역되면 0.0099999처럼 읽습니다 .... 시스템에 따라 (64 비트 컴퓨터는 32 비트보다 훨씬 더 나은 정밀도를 제공합니다. ). 운영 체제는이 경우 인쇄 할 것인지 또는 인쇄 할 수있는 방법으로 인쇄 할 것인지 결정합니다. 따라서, 그들이 그것을 표현하고 싶어하는 방식은 기계에 의존적입니다. 그러나 다른 방법으로 언어 수준으로 보호 될 수 있습니다.

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

이 경우 읽어야하는 방법과 정밀도가 얼마나 필요한지 가르쳐주기 때문입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top