범위를 벗어난 플로트는 정수로 캐스팅할 수 없어요
범위를 벗어난 플로트는 정수로 캐스팅할 수 없어요
플로트 값을 정수 타입으로 캐스팅할 때, 그 플로트 값이 정수 타입이 담을 수 있는 범위를 벗어나 있으면 이런 일이 벌어져요.
본문
플로트를 정수로 바꿀 때 값이 정수 타입의 범위를 벗어나면 컴파일 타임과 런타임에서 모두 문제가 생겨요. 두 경우를 각각 볼게요.
컴파일 타임에는:
comptime {
const float: f32 = 4294967296;
const int: i32 = @intFromFloat(float);
_ = int;
}
$ zig test test_comptime_out_of_bounds_float_to_integer_cast.zig
/home/ci/work/zig-bootstrap/zig/doc/langref/test_comptime_out_of_bounds_float_to_integer_cast.zig:3:36: error: float value '4294967296' cannot be stored in integer type 'i32'
const int: i32 = @intFromFloat(float);
^~~~~
컴파일 타임에 값이 정해져 있는 경우라면, 값이 범위를 벗어난다는 사실을 컴파일러가 바로 잡아서 오류로 알려줘요. 위 예시에서는 f32 값 4294967296을 i32 타입에 담으려다 "이 플로트 값은 이 정수 타입에 저장할 수 없어요"라는 오류가 나는 거죠. i32가 담을 수 있는 최댓값은 2147483647이니까, 4294967296은 명백히 범위 밖이에요.
런타임에는:
pub fn main() void {
var float: f32 = 4294967296; // runtime-known
_ = &float;
const int: i32 = @intFromFloat(float);
_ = int;
}
$ zig build-exe runtime_out_of_bounds_float_to_integer_cast.zig
$ ./runtime_out_of_bounds_float_to_integer_cast
thread 973905 panic: integer part of floating point value out of bounds
/home/ci/work/zig-bootstrap/zig/doc/langref/runtime_out_of_bounds_float_to_integer_cast.zig:4:22: 0x11e82ce in main (runtime_out_of_bounds_float_to_integer_cast.zig)
const int: i32 = @intFromFloat(float);
^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:788:64: 0x11e7bbb in callMain (std.zig)
if (fn_info.param_types.len == 0) return wrapMain(root.main());
^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:248:5: 0x11e75e1 in _start (std.zig)
asm volatile (switch (native_arch) {
^
(process terminated by signal)
반면 값이 런타임에야 정해지는 경우에는, 컴파일러 입장에서는 그 값이 범위 안에 있을지 밖에 있을지 모르죠. 그래서 컴파일 타임 오류 대신 프로그램이 실제로 실행될 때 패닉이 나요. 위 예시처럼 var float로 선언해서 값이 "런타임에 알려지는" 상황을 만들었더니, 실행 중에 "부동소수점 값의 정수 부분이 범위를 벗어났다"는 패닉 메시지와 함께 프로그램이 종료되는 걸 볼 수 있어요.
정리하면, 플로트를 정수로 캐스팅할 때는 값이 항상 대상 정수 타입의 범위 안에 있다는 걸 보장해야 해요. 컴파일 타임 값은 컴파일러가 잡아주고, 런타임 값은 실행 중 패닉으로 이어지니까요.
더 알아보기
- 값을 먼저 범위 안으로 옮긴 뒤 캐스팅하려면 반올림·내림·올림을 함께 쓰는 다른 변환 방식들을 살펴보면 좋아요.
- 범위뿐 아니라 소수점 이하를 어떻게 처리하는지도 함께 보면,
@intFromFloat같은 내장 함수의 동작이 더 잘 이해돼요.