2011-09-28 2 views
3

다음 두 코드를 살펴보고 답변이 많이 다른 이유를 말해주십시오.부동 비교가 다른 결과를 나타냄

#include<stdio.h> 
int main() { 
    float a = 0.9; 
    if(a<0.9) 
     printf("hi"); // This will be the answer 
    else 
     printf("bye"); 
    return 0; 
} 

그리고 우리는 0.8로 0.9을 변경하는 경우, 그 다음 다른 사람의 성명이 인쇄되어 있습니다 :

#include<stdio.h> 
int main() { 
    float a = 0.8; 
    if(a<0.8) 
     printf("hi"); 
    else 
     printf("bye");//this will be the answer 
    return 0; 
} 

왜이 출력 변화를 우리는 단지 하나의 숫자를 변경하면?

+2

너무 극적인하지 마! _ 단 하나의 digit_을 변경하십시오! 임의의 프로그램에서 한자리 수를 변경하면 출력이 변경됩니다. – Shahbaz

+0

또한 내 대답도 읽어보십시오. 나는 처음에 실수를했고 -1을 얻었지만 그것을 편집했다. 문제의 일반적인 해결 방법이 포함되어있다. – Shahbaz

답변

1

부동 소수점이 어떻게 작동하는지 알아야합니다.

부동 소수점은 2의 제곱을 사용하여 표현되며 각 숫자는 2^-x을 나타내는 데 사용됩니다. 여기서 X는 n 번째 숫자입니다. 예를 들어

, 0.011 (이진)

0.25 + 0.125 = 0.375 지금 0.9을 표현하는 시도이다 2^-2 + 2^-3 될 것입니다. 당신은 곤경에 처했습니다. 이것이 32 비트 및 아마도 64 비트 기계로 표현되는 값은 0.9보다 약간 작은 결과를 주며, 0.8의 경우 결과는 정확하고 2의 제곱으로 표현할 수 있습니다..

python 프롬프트를 열어서이 문제를 해결할 수 있습니다. 시도해보고 숫자를 입력하면 결국 ...99999999으로 끝납니다.

+1

@wormsparty :'0.8 '은 단 정밀도 또는 배정도 부동 소수점에서 정확하게 표현할 수 없습니다. –

+0

바이너리로 변환 할 때 0.8과 0.9 모두 반복됩니다. 두 조건이 다르게 작동하게하는 차이점은 무엇입니까? –

+0

문제는 0.8을 float에 넣었 기 때문에 0.8f에 가까운 32 비트의 이진 표현이 가능하다는 것입니다. 이후 비교는 두 배로 이루어 지므로이를 비교하기 위해 float를 64 비트 표현으로 두 번 캐스팅합니다.이 표현은 더 이상 정확히 0.8을 나타내지 않지만 다른 일부는 실제로 가까운 숫자입니다. 변환과 관련이없는 double 0.8와 비교합니다. 자세한 내용은 아래 답변을 참조하십시오. – wormsparty

10

이 오류는 부동 소수점 정확도 및 float 유형을 double 값과 비교하기 때문에 발생합니다. 부동 소수점 리터럴과 비교해보십시오 : if(a<0.8f)

나는 wikipedia article에 따라 읽을 것을 제안합니다.

+0

@ Constantinius : 예, 나는 당신의 설명에 동의한다. 질문에 답하는 것이지만, 왜 똑같은 일이 일어나지 않는지 # include int main() { float a = 0.9; if (a <0.9) printf ("hi"); else printf ("bye"); // 대답이됩니다 return 0; } ur에 대한 답변 bye shud 인쇄는하지만 그렇지 않습니다 ...하지만 0.9에서 0.8로 변경하면 괜찮습니다. –

+0

@Nishant : 0.9의 경우 (부정확 한) 단 정밀도 값이 (부정확 한) 배정 밀도 값을 갖는 반면, 0.8의 경우에는 더 큰 값을 나타냅니다. –

0

먼저 언급 된 다른 항목과 마찬가지로 float으로 작업 할 때 0.8f과 같은 값을 사용하십시오.

또한 부동 소수점 == 비교는 FPU에서이 연산의 정밀도 때문에 피해야 할 사항입니다.

if (LHS == RHS) 

을 당신이 쓰는 : 무엇 항상 나에게 가장 일을하는 대신이의의가 1e-6f (또는 응용 프로그램에 따라 필요로하는 정밀도)을 가정 해 봅시다, 여백을 정의하는 것이었다

if (LHS-RHS < MARGIN && RHS-LHS < MARGIN) 

당신 이 기능은 C++ 팬이라면) 또는 매크로 (만약 당신이 ac 팬이라면 (여기 -1이 나온다)) 쓸 수있다.

5

리터럴 0.90.8의 유형은 double입니다. 두 값을 정확히 나타낼 수 없으므로 실제로는 0.9000000000000000222...0.8000000000000000444...이됩니다. a 변수 float (단 정밀도)에 저장하면

는 단일로 변환 더욱 부정확하게됩니다 0.89999997...0.8000000119...을.

리터럴 값 double과의 비교를 위해 더 정확한 값을 유지하는 double으로 다시 변환됩니다.

위의 수치에서 알 수 있듯이 0.90.8의 결과는 서로 다릅니다.

이 모든 것은 사용자 플랫폼에 IEEE754 플로트가 있다고 가정합니다.

www.binaryconvert.com에서 숫자의 단일/이중 표현을 볼 수 있습니다.

-1

이 시도 :

대신

는 C 표준에 따라 사용 비교 "만약 (A < 0.9f)"

1

"(A < 0.9)의 경우"

6.3. 1.5 실수 형

1) float가 double 또는 long double로 승격되거나 double이 double double로 승격되면은 그 값이 변경되지 않습니다. 이중가 부유 강등 될 때, 긴 더블이 또는 플로트 또는 값을 두배로 강등

2)의 시맨틱 타입에 의해 요구되는 것보다 더 큰 정확성과 범위 표현되는 (명시 적이다) 6.3.1.8 참조 을 의미 유형으로 변환하면 변환되는 값이 정확하게 새 유형으로 표현 된 일 수 있지만 변경되지 않습니다. 변환되는 값 이 표현할 수있는 값의 범위에 있지만 을 정확하게 나타낼 수없는 경우 결과는 또는 가장 가까운 낮은 표현 가능한 값 중 하나이며 구현 방식으로 선택됩니다. 변환되는 값이 표현할 수있는 값 범위 인 외부에 있으면 동작이 정의되지 않은 것입니다.

표준은 here찾을 수 있습니다.

0

경우 생성하기 전에이 당신이 printf와 삽입 사용되는 값을보고, 반올림 오류로 인해 :

printf("a=%f\n", a); 
관련 문제