2011-11-09 5 views
7

위키 백과 (http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion)에서 다음 예제를 우연히 발견했습니다.C에서 암시 적 유형 변환

#include <stdio.h> 

int main() 
{ 
    int i_value = 16777217; 
    float f_value = 16777217.0; 
    printf("The integer is: %i\n", i_value); // 16777217 
    printf("The float is: %f\n", f_value); // 16777216.000000 
    printf("Their equality: %i\n", i_value == f_value); // result is 0 
} 

그들의 설명 : ".이 이상한 행동은이 f_value과 비교하면 떠 i_value의 암시 적 캐스트에 의해 발생, 값을, 정밀도를 잃는 캐스트가 다른 비교되는"

잘못 아니셨습니까? i_value가 float로 형변환 된 경우, 둘 다 동일한 정밀도의 손실을 가지며 동일합니다. 그래서 i_value는 double으로 변환해야합니다.

+0

g ++ (GCC 4.6.2)에서는 동등 함을 위해'1'을 얻습니다. –

+0

@Kerrek : 그리고 나. VS에서 나는 0을 얻습니다. –

+0

@OliCharlesworth : 리터럴을'f' 또는'double'으로 타입 변경하는 것에 대해 궁금합니다 - 모든 경우에'1'을 얻습니다 ... –

답변

7

아니, 항등 연산자의 경우,이 발생 "일반적인 산술 변환이"시작하는 :

  • 첫째, 피연산자의 대응 실제 유형은 long double의 경우 다른 피연산자는 유형 도메인의 변경없이 해당 실제 유형이 long double 인 유형으로 변환됩니다.
  • 다른 실제 피연산자 유형이 double 인 경우 다른 피연산자는 도메인 유형을 변경하지 않고 해당 실제 유형이 double 인 유형으로 변환됩니다.
  • 다른 실제 피연산자 유형이 float 인 경우 다른 피연산자는 도메인 유형을 변경하지 않고 해당 실제 유형이 float 인 유형으로 변환됩니다.

이 마지막 경우 여기에 적용 i_valuefloat로 변환됩니다.부동 피연산자의

값과 부동의 결과 :

이에도 불구하고, 비교 을 이상한 결과를 볼 수있는 이유는, 때문에 일반적인 산술 변환이주의해야 할 점이다 표현식은 형식에서 필요로하는 보다 정밀도와 범위가 더 크게 표현 될 수 있습니다. 그로 인해 유형이 변경되지 않습니다.

이는 무슨 일이 일어나고 있는지입니다 : 변환 된 i_value의 유형은 여전히 ​​float이지만,이 표현에 컴파일러가이 위도을 활용하고 float보다 더 큰 정밀도를 나타내는. 컴파일러는 부동 소수점 숫자를 80 비트 확장 정밀 형식으로 저장하는 부동 소수점 스택에 임시 값을 남겨두기 때문에 387 호환 부동 소수점을 컴파일 할 때 일반적인 컴파일러 동작입니다.

컴파일러가 gcc 인 경우 -ffloat-store 명령 줄 옵션을 사용하여이 추가 정밀도를 사용하지 않도록 설정할 수 있습니다.

+0

x64 gcc에서는 integer를 float로 변환하는 명시 적 cvtsi2ssl 명령을 사용합니다. 그러나 x86에서 이것은 정확하게 발생하며 더 큰 정밀도는 실제로 두 배보다 큽니다. –

+0

@ konrad.kruczynski : 예,'-mfpmath = sse' 옵션 ('-msse' 또는 그 옵션을 요구하는 옵션이 필요합니다)을 제공함으로써 x86에서 동일한 결과를 얻을 수 있습니다. – caf

-1

32 비트 IEEE 부동 소수점이 보유 할 수있는 가장 큰 정수 값은 위의 수보다 작은 1048576입니다. 따라서 부동 소수점 값이 정확히 16777217을 유지하지 못하는 것은 사실입니다.

컴파일러가 두 가지 유형의 숫자 ​​(즉 부동 소수점 및 정수)를 비교하는 방법은 잘 모르겠습니다. . 나는이 작업을 수행 할 수있는 세 가지 방법을 생각할 수 있습니다

1)이 값을 동일해야한다 ("부동"로 두 값을 변환, 그래서 이것은 아마하지 컴파일러가하는 일)

2) 두 값을 모두 "int"로 변환합니다 (정수로 변환하면 int가 자주 자르므로 부동 소수점 값이 16777216.99999 인 경우 "int"로 변환하면 잘립니다)

3) 두 값을 모두 "double"로 변환하십시오. 내 생각 엔이 컴파일러가 할 것입니다. 이것이 컴파일러가하는 것이라면 두 값은 분명히 다릅니다. double은 16777217을 정확하게 저장할 수 있으며 16777217.0이 변환하는 부동 소수점 값을 정확하게 나타낼 수도 있습니다 (정확히 16777217.0은 아닙니다).

+3

1048576은 2^20이므로 잘못된 값입니다. –

0

여기에 몇 가지 좋은 답변이 있습니다. 다양한 정수와 다양한 부동 소수점 표현 사이의 변환을 매우 조심해야합니다.

일반적으로 부동 소수점 숫자는 부동 소수점 숫자를 테스트하지 않습니다. 특히 부동 소수점 숫자 중 하나가 정수 유형의 암시 적 또는 명시 적 형변환 인 경우에는 부동 소수점 숫자를 테스트하지 마십시오. 나는 기하학적 계산으로 가득 찬 응용 프로그램에서 작업합니다. 가능한 한 많이 표준화 된 정수를 사용합니다 (입력 데이터에서 허용 할 수있는 최대 정밀도를 강제합니다). 부동 소수점을 사용해야하는 경우에는 비교가 필요할 경우 차이에 절대 값을 적용합니다.