2012-03-26 9 views
3

저는이 간단한 코드를 시도합니다. 이는 부동으로 표현 될 수없는 제 10 개 정수를 나타낸다 :(float) casting이 작동하지 않습니다.

int main(){ 
    int i, cont=0; 
    float f; 
    double di, df; 
    for(i=10000000, f=i; i<INT_MAX; i++, f=i, df=f, di=((float)i)){ 
    if(i!=f){ 
     printf("i=%d f=%.2f df=%.2lf di=%.2lf\n", i, f, df, di); 
     if(cont++==10) return 0; 
    } 
    } 
    return 1; 
} 

이중 변수이다, 그러나 DF 같아야 그래서, (플로트) 내가로 설정하지만 그렇지 않습니다.

예를 들어, 숫자는 16,777,217 DF 및 f를 의해 16777216로 표현되지만, (플로트) 주조 무시 여전히 16,777,217이다.

어떻게 가능합니까?

** 나는이 사용하고 (우분투 4.4.3-4ubuntu5) 귀하의 질문에 관련 4.4.3

+1

플랫폼 및 컴파일러 버전은 무엇입니까? – sarnold

+3

왜 쉼표 연산자를 사용하고 있습니까? 꼭 필요한 것은 없으며 이와 같이 불필요한 복잡성 문제를 추가합니다. – Joe

+0

당신은'% lf'을 말할 필요가 없습니다. 단지'% f'는 괜찮습니다, 그리고 그것은'double'을 의미합니다. –

답변

2

가 6.3.1.8:2 the C99 standard에 GCC를 : 부동의

값 피연산자 및 부동 결과의 표현은 형식에서 요구하는 것보다 더 높은 정밀도와 범위로 표현 될 수 있습니다 ( ). 그로 인해 유형이 변경되지 않습니다.

특히 각주 52에서

은 :

캐스트와 할당 연산자는 여전히 6.3.1.4 및 6.3.1.5에 설명 된대로 그들의 지정된 변환을 수행해야합니다.

각주를 읽으면 컴파일러에 버그가 있음을 알 수 있습니다.

컴파일러에서 두 가지 버그가 발견되었을 수 있습니다. i!=f 비교는 부동 소수점 사이에서 수행되므로 (표준의 동일한 페이지에있는 승격 규칙 참조) 항상 거짓이어야합니다. 이 후자의 경우 컴파일러에서 6.3.1.8:2 비교를 위해 더 큰 유형을 사용할 수 있다고 생각하지만 아마도이 비교를 (double)i!=(double)f과 동일하게 만들어서 때로는 사실이 될 수 있습니다. 단락 6.3.1.8:2는 내가 가장 싫어하는 표준 단락이며, 여전히 엄격한 앨리어싱을 이해하려고합니다.

+0

고마워요. 제 생각 엔 당신이 맞고 버그 (또는 기능?)가 컴파일러에 있다고 생각합니다. i! = f는 실수 대신 double 값을 비교합니다. – salteador

+0

gcc의 알려진 오랜 버그로, 개발자는 정확성에 신경 쓰지 않는 사람들의 성능을 보통으로 상하게하기 때문에 수정할 것이 거의 없습니다.프로그램이 오래된 cpus와 호환되지 않는 것에 신경 쓰지 않는다면,'-msse'로 문제를 해결할 수 있습니다 (부동 소수점에 FPE 대신 SSE 사용). x86 (및 아마도 m68k?) 이외의 플랫폼에서 문제는 존재하지 않습니다. –

+0

@R .. : 정확도에 상관없이 성능을 최대화하려면 모든 부동 소수점 계산이 42.0을 반환하지 않는 것이 어떻습니까? 그들에게 수학을 가장하는 것보다 빠르지 않을까요? 컴파일러가 중간 값을 32 비트 형식이 아닌 80 비트 확장 형식을 사용하여 * f4 = f1 + f2 + f3;과 같은 것을 수행하는 것이 좋은 IMHO * 그러나 비교와 캐스트가 적절한 유형에서 수행되지 않는다면 의미가 없으며 "속도"는 부적합합니다. – supercat

2

이 포스팅은 무슨 일이 일어나고 있는지 설명 :

http://www.exploringbinary.com/when-floats-dont-behave-like-floats/

기본적으로 추가 정밀이 동일하지 동일 수레 일 것입니다 무슨 만들고, 다른 식 평가의 시스템에 저장 될 수 있습니다.

+0

고마워요. 나는 그것을 모른다;) – salteador

+0

표준은 추가 정밀도를 버리기 위해 캐스트가 필요하다. GCC는이 점에서 간단하게 부러졌으며 알려진 문제입니다. 이 문제는'-ffloat-store' 옵션으로 부분적으로 밟을 수도 있지만, 캐스트가 아닌 할당 만 수정합니다. –

관련 문제