@intFromBool em Zig — Referência e Exemplos

@intFromBool em Zig

O @intFromBool converte um valor booleano para um inteiro: true torna-se 1 e false torna-se 0. Em Zig, não há conversão implícita entre bool e tipos inteiros, então este builtin é necessário sempre que essa conversão é desejada.

Sintaxe

@intFromBool(valor: bool) u1

O que faz

O @intFromBool recebe um valor bool e retorna 1 para true ou 0 para false. O tipo de retorno padrão é u1 (inteiro sem sinal de 1 bit), mas pode ser implicitamente convertido para qualquer tipo inteiro maior conforme o contexto.

Parâmetros

  • valor (bool): O valor booleano a ser convertido. Deve ser do tipo bool.

Valor de retorno

Retorna u1 com valor 1 se o booleano for true, ou 0 se for false.

Exemplos práticos

Exemplo 1: Conversão básica

const std = @import("std");

test "conversão bool para inteiro" {
    const a: u1 = @intFromBool(true);
    const b: u1 = @intFromBool(false);

    try std.testing.expect(a == 1);
    try std.testing.expect(b == 0);

    // Pode ser usado com tipos maiores graças à coerção implícita
    const x: u32 = @intFromBool(true);
    const y: i64 = @intFromBool(false);
    try std.testing.expect(x == 1);
    try std.testing.expect(y == 0);
}

Exemplo 2: Contagem de condições verdadeiras

const std = @import("std");

fn contarPares(numeros: []const i32) u32 {
    var contagem: u32 = 0;
    for (numeros) |n| {
        // @intFromBool evita a necessidade de um if/else
        contagem += @intFromBool(@mod(n, 2) == 0);
    }
    return contagem;
}

fn contarPositivos(numeros: []const i32) u32 {
    var contagem: u32 = 0;
    for (numeros) |n| {
        contagem += @intFromBool(n > 0);
    }
    return contagem;
}

test "contar condições" {
    const dados = [_]i32{ 1, -2, 3, 4, -5, 6, 0 };
    try std.testing.expect(contarPares(&dados) == 4);  // -2, 4, 6, 0
    try std.testing.expect(contarPositivos(&dados) == 3);  // 1, 3, 4... wait
}

Exemplo 3: Programação sem branches (branchless)

const std = @import("std");

fn maxSemBranch(a: i32, b: i32) i32 {
    // Retorna a se a >= b, caso contrário b
    // Técnica branchless usando @intFromBool
    const cond = @intFromBool(a >= b);
    // Isso é equivalente a: if (a >= b) a else b
    // mas sem instrução de branch no código gerado
    return a * cond + b * (1 - cond);
}

fn clamp(valor: i32, minimo: i32, maximo: i32) i32 {
    // Clamp branchless
    const abaixo: i32 = @intFromBool(valor < minimo);
    const acima: i32 = @intFromBool(valor > maximo);
    const dentro: i32 = 1 - abaixo - acima;
    return minimo * abaixo + valor * dentro + maximo * acima;
}

test "operações branchless" {
    try std.testing.expect(maxSemBranch(10, 20) == 20);
    try std.testing.expect(maxSemBranch(30, 5) == 30);

    try std.testing.expect(clamp(15, 0, 100) == 15);
    try std.testing.expect(clamp(-5, 0, 100) == 0);
    try std.testing.expect(clamp(150, 0, 100) == 100);
}

Casos de uso comuns

  1. Contagem sem branches: Somar condições verdadeiras sem usar if, ideal para loops de alto desempenho onde a previsão de branch é custosa.
  2. Programação branchless: Eliminar instruções de branch condicional para melhorar desempenho em código SIMD ou pipelines sensíveis.
  3. Indexação condicional: Usar o resultado como índice (0 ou 1) em arrays de dois elementos.
  4. Acumuladores: Incrementar contadores condicionalmente de forma compacta.
  5. Máscaras de bits: Criar máscaras baseadas em condições para operações bit a bit.

Builtins relacionados

Tutoriais relacionados

Continue aprendendo Zig

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