@intFromFloat em Zig
O @intFromFloat converte um valor de ponto flutuante para um tipo inteiro, truncando a parte fracionária. Diferente de conversões implícitas em C que podem gerar comportamento indefinido, o Zig torna essa conversão explícita e definida, garantindo que o programador esteja ciente da perda de precisão.
Sintaxe
@intFromFloat(valor: anytype) IntType
O tipo de retorno é inferido pelo contexto onde o resultado é usado.
O que faz
O @intFromFloat converte um valor de ponto flutuante (f16, f32, f64, f80, f128) para um tipo inteiro. A parte fracionária é truncada (arredondada em direção a zero). Se o valor estiver fora do intervalo representável pelo tipo inteiro de destino, o resultado é um comportamento de segurança ilegal (safety-checked illegal behavior) — o que em modo debug causa um panic.
Parâmetros
- valor (
anytype): Um valor de ponto flutuante a ser convertido. Deve ser um tipo float válido (f16,f32,f64,f80,f128oucomptime_float).
Valor de retorno
Retorna o valor truncado como o tipo inteiro de destino, inferido pelo contexto. A parte fracionária é descartada.
Exemplos práticos
Exemplo 1: Conversões básicas
const std = @import("std");
test "conversão float para inteiro" {
const a: f64 = 42.7;
const b: f64 = -15.9;
const c: f64 = 0.99;
const x: i32 = @intFromFloat(a);
const y: i32 = @intFromFloat(b);
const z: i32 = @intFromFloat(c);
// Truncamento: parte fracionária é descartada
try std.testing.expect(x == 42); // 42.7 -> 42
try std.testing.expect(y == -15); // -15.9 -> -15 (trunca em direção a zero)
try std.testing.expect(z == 0); // 0.99 -> 0
}
Exemplo 2: Conversão em cálculos gráficos
const std = @import("std");
const Ponto = struct {
x: i32,
y: i32,
};
fn pontoNaTela(x_mundo: f64, y_mundo: f64, escala: f64) Ponto {
return .{
.x = @intFromFloat(x_mundo * escala),
.y = @intFromFloat(y_mundo * escala),
};
}
test "conversão para coordenadas de pixel" {
const ponto = pontoNaTela(3.7, 2.1, 100.0);
try std.testing.expect(ponto.x == 370);
try std.testing.expect(ponto.y == 210);
}
Exemplo 3: Arredondamento antes da conversão
const std = @import("std");
fn arredondar(valor: f64) i64 {
// @intFromFloat trunca, então somamos 0.5 para arredondar
if (valor >= 0) {
return @intFromFloat(valor + 0.5);
} else {
return @intFromFloat(valor - 0.5);
}
}
fn teto(valor: f64) i64 {
const truncado: i64 = @intFromFloat(valor);
const como_float: f64 = @floatFromInt(truncado);
if (como_float < valor) return truncado + 1;
return truncado;
}
test "arredondamento personalizado" {
try std.testing.expect(arredondar(3.7) == 4);
try std.testing.expect(arredondar(3.2) == 3);
try std.testing.expect(arredondar(-2.6) == -3);
try std.testing.expect(teto(3.1) == 4);
try std.testing.expect(teto(3.0) == 3);
try std.testing.expect(teto(-2.3) == -2);
}
Casos de uso comuns
- Renderização gráfica: Converter coordenadas de mundo (float) para coordenadas de pixel (inteiro).
- Processamento de áudio: Converter amostras de ponto flutuante (normalizadas entre -1.0 e 1.0) para valores inteiros de PCM.
- Física e simulação: Converter resultados de cálculos físicos para índices de grade ou posições discretas.
- Formatação de números: Extrair a parte inteira de um número para exibição.
- Quantização: Converter valores contínuos para valores discretos em processamento de sinais.
Cuidados importantes
- Se o valor float for
NaN,+Infou-Inf, a conversão causa panic em modo debug. - Se o valor truncado estiver fora do intervalo do tipo inteiro de destino, também causa panic em modo debug.
- Em modo
ReleaseFast, esses casos resultam em comportamento indefinido, assim como em C.
Builtins relacionados
- @floatFromInt — Operação inversa: converte inteiro para float
- @as — Conversão de tipo genérica
- @intFromEnum — Converte enum para inteiro
- @intFromBool — Converte booleano para inteiro