@subWithOverflow em Zig
O @subWithOverflow realiza uma subtração e indica se houve overflow (ou underflow). Retorna uma tupla com o resultado (possivelmente truncado) e um bit de overflow. Especialmente útil com tipos unsigned, onde subtrair um valor maior causa underflow.
Sintaxe
@subWithOverflow(a: T, b: T) struct { T, u1 }
Parâmetros
- a (
T): Minuendo (tipo inteiro). - b (
T): Subtraendo (mesmo tipo inteiro).
Valor de retorno
Retorna uma tupla struct { T, u1 }:
- [0] (
T): Resultado da subtração (truncado se overflow). - [1] (
u1):1se houve overflow/underflow,0caso contrário.
Exemplos práticos
Exemplo 1: Detecção de underflow em unsigned
const std = @import("std");
pub fn main() void {
// Sem underflow
const r1 = @subWithOverflow(@as(u8, 100), @as(u8, 50));
std.debug.print("100 - 50 = {} (overflow: {})\n", .{ r1[0], r1[1] });
// 100 - 50 = 50 (overflow: 0)
// Com underflow: 50 - 100 em u8
const r2 = @subWithOverflow(@as(u8, 50), @as(u8, 100));
std.debug.print("50 - 100 = {} (overflow: {})\n", .{ r2[0], r2[1] });
// 50 - 100 = 206 (overflow: 1) — wraps around
}
Exemplo 2: Subtração segura com fallback
const std = @import("std");
fn subSegura(a: u32, b: u32) u32 {
const resultado = @subWithOverflow(a, b);
if (resultado[1] != 0) {
return 0; // Saturar em zero em vez de overflow
}
return resultado[0];
}
pub fn main() void {
std.debug.print("{}\n", .{subSegura(100, 30)}); // 70
std.debug.print("{}\n", .{subSegura(10, 50)}); // 0 (saturado)
}
Exemplo 3: Cálculo de diferença absoluta
const std = @import("std");
fn diferencaAbsoluta(a: u32, b: u32) u32 {
const r = @subWithOverflow(a, b);
if (r[1] != 0) {
// a < b, calcular b - a
return b - a;
}
return r[0];
}
pub fn main() void {
std.debug.print("|100 - 30| = {}\n", .{diferencaAbsoluta(100, 30)}); // 70
std.debug.print("|30 - 100| = {}\n", .{diferencaAbsoluta(30, 100)}); // 70
}
Casos de uso comuns
- Aritmética segura: Evitar panic por underflow em tipos unsigned.
- Saturação: Implementar subtração saturante (clampar em zero).
- Diferença absoluta: Calcular distância entre valores sem saber a ordem.
- Timers e contadores: Detectar wrap-around em contadores que decrementam.
Builtins relacionados
- @addWithOverflow — Adição com detecção de overflow
- @mulWithOverflow — Multiplicação com detecção de overflow
- @min / @max — Limitar valores
- @shlExact — Shift left exato