@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 tipobool.
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
- Contagem sem branches: Somar condições verdadeiras sem usar
if, ideal para loops de alto desempenho onde a previsão de branch é custosa. - Programação branchless: Eliminar instruções de branch condicional para melhorar desempenho em código SIMD ou pipelines sensíveis.
- Indexação condicional: Usar o resultado como índice (0 ou 1) em arrays de dois elementos.
- Acumuladores: Incrementar contadores condicionalmente de forma compacta.
- Máscaras de bits: Criar máscaras baseadas em condições para operações bit a bit.
Builtins relacionados
- @intFromEnum — Converte enum para inteiro
- @intFromFloat — Converte float para inteiro
- @intFromPtr — Converte ponteiro para inteiro
- @as — Conversão de tipo genérica