21.39999618530273으로 21.4와 같은 일부 값으로 이중 변수가 초기화되는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/177506

  •  05-07-2019
  •  | 
  •  

문제

double r = 11.631;
double theta = 21.4;

디버거에서 이들은 다음과 같이 표시됩니다 11.631000000000000 그리고 21.399999618530273.

이것을 피하려면 어떻게해야합니까?

도움이 되었습니까?

해결책

이것들 정확도 문제 . 때문입니다 내부 표현 부동 소수점 번호는 피하기 위해 할 수있는 일이 많지 않습니다.

그건 그렇고, 런타임에서 이러한 값을 인쇄하면 종종 최소한 최소한의 C ++ 컴파일러를 사용하여 올바른 결과로 이어집니다. 대부분의 작업에서는 많은 문제가 아닙니다.

다른 팁

좋아 했어요 Joel의 설명, Excel 2007에서 유사한 바이너리 플로팅 포인트 정밀 문제를 다루는 :

마지막에 0110 0110 0110이 얼마나 많이 있는지 보시겠습니까? 그것은 ~ 때문에 0.1 가지다 이진에서 정확한 표현이 없습니다... 반복되는 이진수입니다. 1/3이 소수점에서 표현이없는 방법과 같습니다. 1/3은 0.33333333입니다. 인내심을 잃으면 무언가를 얻지 못합니다.

따라서 10 진수로 3*1/3을 시도하고 3을 영원히 쓸 시간이 없다면 결과는 1이 아닌 0.9999999, 사람들이 화를내는 방법을 상상할 수 있습니다. 당신은 잘못 되었기 때문에.

다음과 같은 값이있는 경우 :

double theta = 21.4;

그리고 당신은하고 싶습니다 :

if (theta == 21.4)
{
}

당신은 약간 영리해야합니다. Theta의 가치가 있는지 확인해야합니다. 진짜 21.4에 가깝지만 반드시 그 가치는 아닙니다.

if (fabs(theta - 21.4) <= 1e-6)
{
}

이것은 부분적으로 플랫폼 별이며 어떤 플랫폼을 사용하고 있는지 모릅니다.

또한 부분적으로 당신이 실제로 무엇을 아는 경우이기도합니다. 원하다 보다. 디버거는 변수에 저장된 정확한 값을 어느 정도까지 보여줍니다. 내 .NET의 이진 부동 소수점 번호에 관한 기사, 거기에 C# 클래스 절대적으로 볼 수 있습니다 정확한 숫자는 두 배로 저장됩니다. 온라인 버전은 현재 작동하지 않습니다. 다른 사이트에 하나를 올리려고 노력할 것입니다.

디버거가 "실제"값을보고 있다는 점을 감안할 때, 표시 할 내용에 대한 판단을 내려야합니다. 소수점 이하의 자리 또는보다 정확한 값으로 반올림 된 값을 보여줄 수 있습니다. 일부 디버거는 개발자의 마음을 읽는 데있어 다른 디버거보다 더 나은 일을하지만 바이너리 플로팅 포인트 번호의 근본적인 문제입니다.

고정점을 사용하십시오 decimal 정밀 한계에서 안정성을 원한다면 입력하십시오. 오버 헤드가 있으며 부동 소수점으로 변환하려면 명시 적으로 캐스트해야합니다. 당신이 부동 소수점으로 변환한다면 당신은 당신을 괴롭히는 것처럼 보이는 불안정성을 다시 소개 할 것입니다.

또는 당신은 그것을 극복하고 일하는 법을 배울 수 있습니다 ~와 함께 부동 소수점 산술의 제한된 정밀도. 예를 들어, 반올림을 사용하여 값이 수렴되거나 Epsilon 비교를 사용하여 공차를 설명 할 수 있습니다. "Epsilon"은 공차를 정의하는 상수입니다. 예를 들어, 두 값이 서로 0.0001 내에있는 경우 동일하다고 간주 할 수 있습니다.

Epsilon 비교를 투명하게 만들기 위해 연산자 과부하를 사용할 수 있습니다. 그것은 매우 시원 할 것입니다.


Mantissa-exponent 표현의 경우 Epsilon은 대표적 정밀도 내에 남아 있도록 계산되어야합니다. 숫자 n의 경우, Epsilon = n / 10e+14

System.Double.Epsilon 가장 작은 대표적 긍정적 값입니다 Double 유형. 그것은이다 ~도 우리의 목적을 위해 작습니다. 읽다 평등 테스트에 대한 Microsoft의 조언

나는 전에 이것을 만난다 (내 블로그에서) - 나는 놀라움이 '비이성적 인'숫자가 다르다는 경향이 있다고 생각합니다.

'비이성적'이라는 말로 나는 단지 그들이이 형식으로 정확하게 표현할 수 없다는 사실을 언급하고 있습니다. 실제 비이성적 인 숫자 (예 : π -pi)는 전혀 정확하게 표현할 수 없습니다.

대부분의 사람들은 1/3에 익숙합니다. 소수점에서 작동하지 않습니다 : 0.333333333333 ...

이상한 점은 1.1이 플로트에서 작동하지 않는다는 것입니다. 사람들은 소수점 값이 떠 다니는 지점에서 작동 할 것으로 예상합니다.

1.1은 11 x 10^-1입니다

실제로 그들은베이스 2에 있습니다

1.1은 154811237190861 x 2^-47입니다

당신은 그것을 피할 수 없습니다. 당신은 1/3과 같은 방식으로 일부 수레가 '비이성적'이라는 사실에 익숙해 져야합니다.

이를 피할 수있는 한 가지 방법은 소수점 번호를 나타내는 대체 방법을 사용하는 라이브러리를 사용하는 것입니다. BCD

21.39999618530273이 단일 정밀도 (플로트) 21.4의 표현. 디버거가 더블에서 어딘가에 부유 한 것처럼 보입니다.

Java를 사용하고 있고 정확도가 필요한 경우 Bigdecimal 클래스를 사용하여 플로팅 포인트 계산에 사용하십시오. 느리지 만 더 안전합니다.

고정 된 양의 바이트가있는 부동 소수점 번호를 사용하므로 피할 수 없습니다. 실수와 제한된 표기법 사이에는 동형이 불가능합니다.

그러나 대부분의 경우 단순히 무시할 수 있습니다. 21.4 == 21.4는 여전히 같은 오류가있는 동일한 숫자이기 때문에 여전히 사실입니다. 그러나 21.4f == 21.4는 플로트와 더블의 오류가 다르기 때문에 사실이 아닐 수 있습니다.

고정 정밀도가 필요한 경우 고정점 번호를 사용해야합니다. 또는 정수. 예를 들어, 디버그 호출기로 통과하기 위해 int (1000*x)를 사용합니다.

귀찮게하면 디버그 중에 일부 값이 표시되는 방식을 사용자 정의 할 수 있습니다. 조심스럽게 사용하십시오 :-)

디버거 디스플레이 속성으로 디버깅 향상

인용하다 일반 소수점 산술

플로트를 비교할 때도 참고하십시오 이 답변 자세한 내용은.

Javadoc에 따르면

"수치 연산자에 대한 피연산자 중 하나 이상이 두 배의 유형이라면
작전은 64 비트 부동 소수점 산술을 사용하여 수행되며 결과는
수치 연산자는 유형의 값입니다. 다른 피연산자가 더블이 아닌 경우
숫자 프로모션 (§5.6)에 의해 더블을 입력하도록 먼저 확대 (§5.1.5). "

여기 소스가 있습니다

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