C언어에서 형의 변환 - 2

CHOI·2021년 6월 18일
1

C 언어

목록 보기
12/28
post-thumbnail

앞선 포스팅에서 한 가지 의문점을 가지고 마무리 했었다.

float의 지수의 범위가 0~255 가 아니고 1~254일까???

당연히 들 수 있는 의문점이다 float의 지수가 8비트이니까 당연히 0부터 255까지라고 생각할 수 있다. 좋은 질문이다. 0 과 255 가 포함되지 않는 이유는 IEEE 754 에서 아래와 같이 정상적이지 않는 수를 표현하기 위해서 다음과 같이 규칙을 정했기 때문이다.

참고로 각 수에 대해 설명을 하자면

비정상 수(Denormalized number)

비정상 수는 21272^{-127}보다 작아서 지수 부분에 바이어스 처리를 하여도 1보다 작은 수를 말한다. 따라서 이 경우에는 더이상 1.(가수부분)21271.(가수부분)*2^{-127} 꼴로 표현할 수 없다. 따라서 이러한 수들을 그 대신 0.(가수부분)21270.(가수부분)*2^{-127} 의 형태로 해석된다.

무한대

부호 비트 덕분에 IEEE 754 방식으로 음의 무한대와 양의 무한대를 표현할 수 있다. 무한대는 연산하는 과정에서 표현할 수 있는 가장 큰 수 보다 큰 값이 들어가면 자동으로 발생하게 된다.

#include<stdio.h>
int main () {
    float a = 1. / 0.f;
    printf("a : %f \n", a);
    return 0;
}

위 코드를 실행해보면 'inf'라는 무한대 결과가 나오는 것을 알 수 있다.

수가 아님 (NaN)

마지막은 바로 수가 아닌(Not-a-Number) 녀석들이다. 이 녀석들은 다음과 같이 엄밀히 값을 정할 수 없는 연산중에 발생한다. 예를 들어
,+,0×,0÷0,÷,+,0×,0÷0,÷\infty-\infty, -\infty+\infty, 0 \times \infty, 0 \div 0, \infty \div \infty∞−∞,−∞+∞,0×∞,0÷0,∞÷∞ 등이 있다.

형 변환(캐스팅)

다시 처음으로 돌아서 정수형 데이터에 소수형 데이터를 넣을 때 우리는 경고가 발생하지 않고 대입할 수는 없을까? 물론 방법이 있다. 서로의 형을 맞추면 된다.

#include <stdio.h>
int main() {
  int a;
  double b;

  b = 2.4;
  a = (int)b;

  printf("%d \n", a);
}

위와 같이 실행해보면 이전과 같이 2가 출력되지만 오류가 발생하지 않는 것을 볼 수 있다.

이유는 강제로 소수형을 정수형으로 바꾸었기 때문이다.

어떠한 변수의 형을 강제로 바꿀 때 다음과 같이 하면 된다.

(바꾸려는 형) 변수 이름

위의 예시의 경우 double 형인 b(int)b 함으로 정수형으로 바꾼 것이다. 그런데 이때 형을 바꾸는 것은 영구적으로 바꾸는 것이 아니다.

잠시 연산을 위해서 계산식에서 bint 형으로 바뀐 것이지 영구적으로 b 가 정수형이 되는 것이 아니다. 즉 캐스팅을 하고도

printf("%f", b); // 2.4

를 하면 정상적으로 2.4 가 나온다. 이처럼 강제로 형을 변환하면 컴퓨터는 '이 사람이 마음먹고 아예 형이 다른 변수들의 대입을 시도하는 것이구나' 라고 인식하여 경고를 하지 않는 것이다.

다음 예시를 보자

#include<stdio.h>
int main(){
    int a, b;
    float c, d;
    printf("두 숫자를 입력하세요: ");
    scanf("%d %d", &a, &b);
    c = a / b;
    d = (float)a / b;
    
    printf("두 수의 비율: %f %f \n", c, d);
    return 0;
}

매우 흥미로운 결과를 볼 수 있다. cd 의 차이는 단지 변수 하나의 형을 소수로 변환해줬을 뿐인데 하나는 1이 나오고 하나는 1.6666667 이라는 전혀 다른 값이 나온다. 이렇게 결과가 다르게 나오는 이유가 무엇일까?

컴퓨터에서 a / b 는 2가지를 의미한다. a와 b중 어느 하나라도 소수형 변수(float,double)이면 우리가 실제로 원하는 나눗셈을 실행하게 된다 즉 5/3 =1.666666666 를 수행한다. 그런데 만약 둘다 정수형 변수(int, char ,long)이라면 컴퓨터는 a / b 를 보고 나눗셈을 실행하지 않고 소위 말하는 '몫' 을 계산하게 된다. 따라서 5/3 = 1 이 되는 것이다.

따라서 (float)a / b 를 하게 되면 컴퓨터는 a 를 실수형으로 인식하여 몫을 계산하지 않고 정말로 실수형 나눗셈을 수행하게 된다.

이렇게 형변환 하나만 가지고도 값이 크게 바뀐다. 실제로 C언어에서 형변환은 매우 중요한 부분중 하나고 또한 쓰임세도 상당히 많은데 주로 실수형 변수에서 정수값만 추출할 때 자주 사용한다.

예를 들어서 double a; int b; 일 때 b = (int)a; 라 하여 변수 a 에 정수 부분 데이터만 들어가게 된다.

물론 그냥 b = a 를 하여도 정수값만 들어가겠지만 다른 프로그래머들이 봤을 때 이것이 의도적으로 한 것인지 실수 인지 알 수 없기 때문에 오해의 소지가 있다.

profile
벨로그보단 티스토리를 사용합니다! https://flight-developer-stroy.tistory.com/

0개의 댓글