@min em Zig — Referência e Exemplos

@min em Zig

O @min retorna o menor de dois valores. Funciona com inteiros, floats e valores comptime. Se os dois valores forem conhecidos em comptime, o resultado também é comptime. Este builtin substitui a necessidade de escrever expressões condicionais if (a < b) a else b.

Sintaxe

@min(a: T, b: T) T

Parâmetros

  • a (T): Primeiro valor.
  • b (T): Segundo valor (mesmo tipo ou coercível).

Valor de retorno

Retorna T — o menor dos dois valores.

Exemplos práticos

Exemplo 1: Uso básico com inteiros e floats

const std = @import("std");

pub fn main() void {
    const a: u32 = 42;
    const b: u32 = 100;

    std.debug.print("min({}, {}) = {}\n", .{ a, b, @min(a, b) }); // 42

    const x: f64 = 3.14;
    const y: f64 = 2.71;
    std.debug.print("min({d}, {d}) = {d}\n", .{ x, y, @min(x, y) }); // 2.71
}

Exemplo 2: Limitar tamanho de buffer

const std = @import("std");

fn copiarLimitado(destino: []u8, origem: []const u8) usize {
    const tamanho = @min(destino.len, origem.len);
    @memcpy(destino[0..tamanho], origem[0..tamanho]);
    return tamanho;
}

pub fn main() void {
    var buffer: [5]u8 = undefined;
    const texto = "Hello, Zig Brasil!";

    const copiados = copiarLimitado(&buffer, texto);
    std.debug.print("Copiados: {s} ({} bytes)\n", .{ buffer[0..copiados], copiados });
    // "Hello" (5 bytes)
}

Exemplo 3: Clamp (limitar a intervalo)

const std = @import("std");

fn clamp(valor: i32, minimo: i32, maximo: i32) i32 {
    return @max(minimo, @min(valor, maximo));
}

pub fn main() void {
    std.debug.print("{}\n", .{clamp(5, 0, 10)});    // 5 (dentro do intervalo)
    std.debug.print("{}\n", .{clamp(-3, 0, 10)});   // 0 (abaixo do mínimo)
    std.debug.print("{}\n", .{clamp(15, 0, 10)});   // 10 (acima do máximo)
}

Casos de uso comuns

  1. Limitar tamanho: Garantir que um índice não exceda o tamanho do array.
  2. Clamping: Combinar com @max para restringir valores a um intervalo.
  3. Processamento de dados: Encontrar mínimo em sequências.
  4. Dimensionamento: Limitar tamanho de buffers, janelas, etc.

Padrão idiomático: copiar com limite seguro

O uso mais frequente de @min em Zig é garantir que uma operação de cópia ou acesso não ultrapasse o tamanho disponível:

fn appendLimitado(destino: *[128]u8, pos: *usize, origem: []const u8) void {
    const espaco_restante = destino.len - pos.*;
    const a_copiar = @min(origem.len, espaco_restante);
    @memcpy(destino[pos.*..][0..a_copiar], origem[0..a_copiar]);
    pos.* += a_copiar;
}

Esse padrão elimina verificações manuais de bounds e garante que nunca haverá buffer overflow.

Comportamento com floats e NaN

Assim como @max, o @min segue a semântica do IEEE 754: se um dos operandos for NaN, o resultado é o outro operando:

const nan = std.math.nan(f64);
const resultado = @min(nan, 5.0); // resultado == 5.0 (NaN não se propaga)

Isso pode ser surpreendente, mas é o comportamento padrão do IEEE 754-2008 para minNum. Se você precisa que NaN se propague, verifique explicitamente com std.math.isNan antes de chamar @min.

Comparação com C equivalente

Em C, não há função min na biblioteca padrão para todos os tipos. As abordagens comuns têm problemas:

// Macro com avaliação dupla — perigosa com side effects
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int x = MIN(++a, ++b); // BUG: a ou b incrementado duas vezes!

// C99 em <math.h> — apenas para double
double m = fmin(x, y);

Em Zig, @min é um builtin seguro, genérico e sem avaliação dupla:

const m = @min(a, b); // sem side effects duplicados, qualquer tipo numérico

@min com @max para clamping robusto

A combinação dos dois builtins é o idioma padrão para clamping em Zig:

// Garantir que volume fique entre 0.0 e 1.0
const volume_seguro = @max(0.0, @min(volume_entrada, 1.0));

// Garantir que índice seja válido para o array
const indice_seguro = @min(indice, array.len - 1);

// Limitar latência entre 100ms e 30000ms
const latencia_ms = @max(@as(u32, 100), @min(latencia_config, 30_000));

Esse padrão é tão comum que a biblioteca padrão oferece std.math.clamp(val, min, max) como atalho.

Perguntas Frequentes

P: @min funciona com vetores SIMD (@Vector)?

Sim. Assim como @max, o @min é compatível com @Vector. O compilador pode gerar instruções SIMD como vminps (AVX) ou vminss para comparações paralelas de múltiplos valores, o que é muito mais eficiente que comparar elemento a elemento em um loop.

P: Há diferença de performance entre @min(a, b) e if (a < b) a else b?

Em otimizações habilitadas, o compilador geralmente gera o mesmo código para ambos. No entanto, @min comunica a intenção mais claramente e pode ser mais facilmente vetorizado pelo compilador. Para código de performance crítica, prefira @min.

P: @min funciona com tipos comptime_int e comptime_float?

Sim. Se ambos os operandos forem comptime, o resultado também é comptime e o cálculo ocorre inteiramente em tempo de compilação sem custo em runtime. Isso é útil para calcular constantes comptime como tamanhos de arrays.

Builtins relacionados

  • @max — Retorna o maior de dois valores
  • @addWithOverflow — Aritmética com detecção de overflow
  • @as — Conversão de tipo quando os operandos diferem

Tutoriais relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.