부동소수점의 암시적 변환 (대입의 경우)

해당 링크에서는 전반적인 Implicit conversions를 모두 다루지만, 이 포스팅에서는 부동소수점의 암시적 변환만 다룬다,

 

캐스팅에 대한 일부분의 내용을 다루자면 다음 내용이 존재한다:

  • 암시적 변환은 특정 유형의 T1의 표현식이 해당 유형을 허용하지 않지만, 다른 유형 T2를 허용하는 컨텍스트에서 사용될 때 수행된다.
  • T1 → T2까지의 하나의 명확한 암시적 변환 시퀀스가 존재하는 경우에만 프로그램이 잘 컴파일 된다. 산술 표현식에서 피연산자를 이진 연산자로 변환하는 대상 유형은 별도의 규칙 집합인 일반적인 산술 변환에 의해 결정된다.

 

Floating-point promotion

float 타입의 prvalue는 double 타입의 prvalue로 변환할 수 있다. 이를 floating-point promotion이라고 한다. 참고로 promotion은 작은 데이터 타입의 값을 더 큰 데이터 타입으로 자동 변환하는 것이다. 

 

Numeric conversions

promotion과 달리 수치 변환은 값이 바뀔 수 있으며, 정확도가 떨어질 수 있다.

 

Floating-point conversions

C++ 23까지는 부동소수점 타입의 prvalue는 다른 부동소수점 타입의 prvalue로 변화할 수 있다. 

  • 소스 값을 대상 유형으로 정확하게 표현할 수 있는 경우 변경되지 않는다.
  • 만약 소스 값이 대상 타입의 표현 가능한 두 값 사이에 있는 경우 결과는 두 값 중 하나가 된다. (IEEE 산술이 지원되는 경우 반올림은 기본적으로 가장 가까운 값으로 설정되지만 구현에서 정의된다.) 

참고로 C++23 이후의 설명은 조금 더 추가 되어 있다.

  • A prvalue of a floating-point type can be converted to a prvalue of any other floating-point type with a greater or equal floating-point conversion rank.
  • A prvalue of a standard floating-point type can be converted to a prvalue of any other standard floating-point type.
  • static_cast can be used to explicitly convert a prvalue of floating-point type to any other floating-point type.

 

Floating-integral conversions

부동 소수점 타입의 pr값은 모든 정수 타입의 pr값으로 변환할 수 있다. 그리고 분수 부분은 절삭처리되므로 그대로 버려진다.

  • 잘린값이 대상 자료형에 맞지 않으면 동작이 정의도지 않는다(심지어 대상 자료형이 unsigned라면, 모듈러  연산이 적용되지 않는다).
  • 대상 자료형이 bool이면, 이는 boolean conversion이 발생한다.

정수 또는 범위가 지정되지 않은 enum 타입의 pr값은 모든 부동 소수점 타입의 pr값으로 변환할 수 있다. 가능한 결과가 정확하게 나오기는 한다.

  • 값이 대상 타입에 맞지만 정확히 표현할 수 없는 경우, 가장 가까운 상위 값 또는 가장 가까운 하위 값을 선택할지 여부는 구현에 따라 정의되지만, IEEE 산술이 지원되는 경우 반올림은 기본적으로 가장 가까운 값으로 설정된다.
  • 값이 대상 자료형에 맞지 않으면 동작이 정의되지 않는다. (컴파일되지 않는다고 생각하면 된다)
  • 원본 타입이 bool인 경우, false값은 0으로 변환되고 true는 1로 변환된다.

 

Usual arithmetic conversions (이항 연산의 경우, 부동소수점의 암시적 변환 확인 가능)

산술 또는 열거 타입의 피연산자를 기대하는 많은 이항 연산자는 비슷한 방식으로 타입 변환을 일으키고 결과 타입을 산출한다. 그 목적은 결과 타입으로 공통의 타입을 산출하는 것이다. 이러한 패턴을 usual arithmetic conversion 이라고 한다. 이는 다음과 같이 정의 된다.

 

Stage 1

두 피연산자 모두에 lvalue에서 rvalue로의 변환을 적용하고, 그 결과로 생성된 prvalue가 나머지 프로세스에서 원래 피연산자 대신 사용된다.

  • Lvalue-to-Rvalue 변환은 말그대로 lvalue에서 rvalue로 변환되는 것을 의미한다. 여기선 산술 연산에서 변수에 저장된 값을 불러올 때 lvalue-to-rvalue가 수행된다.
  • 즉, 변수의 값을 읽는 순간 lvalue-to-rvalue 변환이 일어나며, 참조를 읽을 때는 변환되지 않는다.

Stage 2

  • 피연사자 중 하나가 범위가 지정된 열거형인 경우 conversion이 수행되지 않으며, 다른 피연산자가 같은 타입이 아닌 경우 표현식이 잘못 형성된다.
  • 그렇지 않으면 다음 단계로 진행된다.

Stage 3

  • 피연서자 중 하나가 열거형이고 다른 피연산자가 다른 열거형 또는 부동 소수점인 경우는 표현식이 올바르지 않은 형식이다.
  • 그렇지 않으면 다음 단계로 진행한다.

Stage 4

  • 피연산자 중 하나가 부동 소수점인 경우, 다음 규칙이 적용된다.
    • 두 피연산자의 타입이 모두 같으면 변환은 수행되지 않는다.
    • 그렇지 않으면, 피연산자 중 하나가 부동 소수점 유형이 아닌 경우 해당 피연산자는 다른 피연산자의 유형으로 변환된다.
    • 그렇지 않으면, 피연산자 타입의 floating-point conversion rank가 같지 않다면 부동 소수점 변환 순위가 낮은 타입의 피연산자가 다른 피연산자의 타입으로 변환된다. (즉, rank가 낮은 타입의 피연산자가 높은 rank의 피연산자에 맞춰 변환된다. double과 float의 연산이 존재한다면 float에서 promotion이 발생.)
    • 그렇지 않으면, 피연산자의 floating-point conversion rank가 동일하다면 floating-point conversion subrank가 더 낮은 피연산자가 다른 피연산자의 타입으로 변환된다.
    • 그렇지 않으면, 이 표현식은 올바르지 않은 것이다.
  • 그렇지 않으면, 두 피연산자가 모두 정수형인 경우 다음 단계로 진행한다.

 

 

Stage 5

피연산자의 promoted type으로 T1 및 T2 타입이 주어지면 두 피연산자는 공통 유형 C로 변환되며 다음 규칙을 적용하여 C를 결정한다:

  • T1과 T2가 같은 타입이면 C는 그 타입 그대로.
  • T1과 T2가 둘 다 signed 또는 둘 다 unsigned면, 더 높은 integer conversion rank를 가진 타입을 C로 설정.
  • T1과 T2들이 하나는 signed integer(S)이고, 나머지 하나는 unsigned integer(U)라면 다음 규칙을 적용
    • U의 integer conversion rank가 S의 integer conversion rank보다 크거나 같으면 C는 U이다.
    • S가 U의 모든 값을 표현할 수 있다면 C는 S
    • 위 두 경우가 아니라면 C는 S에 해당하는 unsigned 타입. 즉, U의 integer conversion rank가 S의 integer conversion rank 보다 낮고, S가 U의 모든값을 표현할 수 없다면 C는 S에 해당하는 unsigned 타입이 된다.
      • U: Unsigned short : 5
      • S: short : -5
      • C: Unsigned short
  • 하나의 피연산자가 열거형이고 다른 피연산자가 다른 열거형 또는 부동 소수점인 경우 이 동작은 더 이상 사용되지 않는다.

 

 

 

참고 자료

 

'C,C++' 카테고리의 다른 글

[C++] Bitwise not 연산  (0) 2025.02.11
[C++] 상수와 포인터  (0) 2023.01.24
C언어 string.h 문자열 관련 함수 정리  (0) 2021.01.09
C언어 표준함수 확인  (0) 2021.01.09
[C언어] 배열을 초과해서 데이터 삽입  (0) 2021.01.07