[c#] 실수형을 반환하는 math.round와 숫자 타입의 형 변환

Rounds a value to the nearest integer or to the specified number of fractional digits.
Math.Round Method

math.round는 분명히 정수를 반환하지만 이게 정수형으로 반환한다는 의미는 아니다. 이 메떠드는 정수를 double이나 decimal 같은 실수형으로 반환한다. 왜 이럴까? int, double, decimal에서 신뢰할 수 있는 자리수는 모두 다르기 때문이다. 더 구체적으로는 int의 그것이 제일 작아서 그렇다. 큰 자리수에 작은 자리수를 넣을 수는 있지만 그 반대는 값을 왜곡하지 않는 한 가능하지 않다. 따라서 반환된 값을 정수로 이용하려면 번거롭게도 정수로 형 변환을 해야 한다. 반올림을 하지 않고 정수형 변환만 하면 버림(floor)이 되는 것에 유의한다.

아래의 코드는 처리되지 않는다.

int int1;

int1 = (int)Math.Round(3 / 2);

round는 패러미터로 double과 decimal을 받아 오버로드되는데 아규먼트가 명시적으로 선언된 변수가 아니라 값이면 컴파일러는 이걸 떠블로 처리해야 할지 데씨멀로 다뤄야 할지를 모르기 때문이다. 라운드는 반올림된 값을 구하기 위해 실수들의 크기를 비교해야 한다. 예를 들어 3 / 2를 반올림할 건지 말 건지 판단하기 위해서는 그 값이 1.5보다 큰지 작은지 같은지를 알아야 한다. 이렇게 실수들의 크기를 비교하는 데에 있어 떠블과 데씨멀에는 큰 차이가 있다. 이 문제를 피하려면 아래와 같이 명시적으로 캐스트를 해 줘야 한다.

int1 = (int)Math.Round((double)3 / 2);

cast는 ‘배역을 준다’, ‘주조한다’는 뜻이다. 무언가를 빼도 박도 못하게 분명히 한다는 의미다. type convert, type cast, typecast로 표현하기도 한다. 위 예제의 경우 엄밀하게는 형 변환이 아니라 형 고정이다.

값들로 구성된 연산을 캐스트할 때에는 식을 괄호로 묶지 않아도 된다. 아래의 두 구문들은 같다.

int1 = (int)3 / 2;
int1 = (int)(3 / 2);

그러나 변수들로 구성된 연산의 경우에는 다르므로 주의한다. 아래의 두 구문들은 서로 다르며 두 번째 것만 작동한다.

double double1 = 0.1;
double double2 = 0.2;

int int1;
                
int1 = (int)double1 + double2; // exception
int1 = (int)(double1 + double2); // 0 -> floor