Exact Division Remainder — 정확히 나눠떨어질 때만 쓰는 나눗셈

Exact Division Remainder — 정확히 나눠떨어질 때만 쓰는 나눗셈

출처: Zig Documentation

본문

@divExact는 이름 그대로 나눗셈이 정확히 나눠떨어질 때만 쓰는 내장 함수예요. 이전에 다뤘던 나눗셈 계열 내장 함수들과 다른 점은, 결과에 나머지가 생기면 안 된다는 조건이 걸려 있다는 거예요. 그러면 정확히 나눠떨어지지 않을 때는 어떤 일이 벌어질까요? 컴파일 타임과 런타임에서 그 모습이 조금 달라요. 하나씩 볼게요.

먼저 컴파일 타임(comptime) 상황입니다.

컴파일 타임:

comptime {
    const a: u32 = 10;
    const b: u32 = 3;
    const c = @divExact(a, b);
    _ = c;
}

여기서 103으로 나누면 몫은 3이고 나머지 1이 남죠. 정확히 나눠떨어지지 않으니 컴파일러가 이걸 검사해서 컴파일 에러로 처리해요.

$ zig test test_comptime_divExact_remainder.zig
/home/ci/work/zig-bootstrap/zig/doc/langref/test_comptime_divExact_remainder.zig:4:15: error: exact division produced remainder
    const c = @divExact(a, b);
              ^~~~~~~~~~~~~~~

이제 런타임 상황을 볼게요.

런타임:

const std = @import("std");

pub fn main() void {
    var a: u32 = 10;
    var b: u32 = 3;
    _ = .{ &a, &b };
    const c = @divExact(a, b);
    std.debug.print("value: {}\n", .{c});
}

여기서는 abvar로 선언돼 있어서 값이 컴파일 타임에 확정되지 않아요. 그래서 컴파일러가 미리 검사할 수 없고, 프로그램이 실제로 실행되는 순간까지 갑니다. 실행하면 기대만큼 value: 3 같은 값이 찍히는 게 아니라, 나눗셈에 나머지가 생겼다며 패닉(panic) 이 발생해요.

$ zig build-exe runtime_divExact_remainder.zig
$ ./runtime_divExact_remainder
thread 973431 panic: exact division produced remainder
/home/ci/work/zig-bootstrap/zig/doc/langref/runtime_divExact_remainder.zig:7:15: 0x11e82e5 in main (runtime_divExact_remainder.zig)
    const c = @divExact(a, b);
              ^
/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)

정리하면 이렇게 볼 수 있어요. @divExact나눠떨어지는 게 보장된 값에만 써야 해요. 만약 나머지가 생길 가능성이 있는 경우라면, 나눗셈 결과가 정확하다는 게 컴파일 타임에는 보장되지 않으니 런타임 패닉까지 이어질 수 있다는 점을 미리 인지하고 있어야 하죠. 값이 컴파일 타임에 알려진 상수라면 컴파일 에러, 실행 시에야 알 수 있는 값이라면 런타임 패닉으로 잡힌다는 차이만 기억하면 돼요.

더 알아보기

  • @divExact는 나머지 없이 정확히 나눠떨어지는 나눗셈을 수행하고, 나머지가 생기면 컴파일 에러 또는 런타임 패닉으로 이어져요.
  • 컴파일 타임 검사가 가능한(comptime) 값은 에러로, 실행 중에만 알 수 있는 값은 패닉으로 처리돼요.
  • 나머지가 있어도 되는 일반적인 나눗셈에는 @divFloor·@divTrunc 같은 다른 내장 함수를 써요.