std.math em Zig — Referência e Exemplos

std.math — Funções Matemáticas

O módulo std.math fornece funções matemáticas fundamentais, constantes, operações de aritmética segura e utilitários para trabalhar com números inteiros e de ponto flutuante. Ele é projetado para segurança — muitas operações que seriam undefined behavior em C retornam erros ou valores bem definidos no Zig.

Visão Geral

const std = @import("std");
const math = std.math;

Constantes

math.pi          // 3.14159265358979...
math.e           // 2.71828182845904...
math.tau         // 6.28318530717958... (2*pi)
math.inf(f64)    // Infinito positivo
math.nan(f64)    // NaN
math.floatMin(f64)  // Menor float positivo normalizado
math.floatMax(f64)  // Maior float representável
math.maxInt(i32)    // 2147483647
math.minInt(i32)    // -2147483648

Funções Principais

Aritmética Segura

// Adição com detecção de overflow
pub fn add(comptime T: type, a: T, b: T) error{Overflow}!T

// Subtração com detecção de overflow
pub fn sub(comptime T: type, a: T, b: T) error{Overflow}!T

// Multiplicação com detecção de overflow
pub fn mul(comptime T: type, a: T, b: T) error{Overflow}!T

// Negação segura
pub fn negate(a: anytype) error{Overflow}!@TypeOf(a)

// Valor absoluto
pub fn absInt(a: anytype) error{Overflow}!@TypeOf(a)

// Casting seguro entre tipos numéricos
pub fn cast(comptime T: type, x: anytype) ?T

Funções Trigonométricas e Exponenciais

pub fn sin(x: anytype) @TypeOf(x)
pub fn cos(x: anytype) @TypeOf(x)
pub fn tan(x: anytype) @TypeOf(x)
pub fn asin(x: anytype) @TypeOf(x)
pub fn acos(x: anytype) @TypeOf(x)
pub fn atan(x: anytype) @TypeOf(x)
pub fn atan2(y: anytype, x: anytype) @TypeOf(y)
pub fn exp(x: anytype) @TypeOf(x)
pub fn exp2(x: anytype) @TypeOf(x)
pub fn log(x: anytype) @TypeOf(x)
pub fn log2(x: anytype) @TypeOf(x)
pub fn log10(x: anytype) @TypeOf(x)
pub fn sqrt(x: anytype) @TypeOf(x)
pub fn pow(comptime T: type, base: T, exp: T) T

Utilitários

pub fn min(a: anytype, b: anytype) @TypeOf(a)
pub fn max(a: anytype, b: anytype) @TypeOf(a)
pub fn clamp(val: anytype, lower: anytype, upper: anytype) @TypeOf(val)
pub fn divCeil(comptime T: type, a: T, b: T) T
pub fn divFloor(comptime T: type, a: T, b: T) T
pub fn order(a: anytype, b: anytype) Order
pub fn isNan(x: anytype) bool
pub fn isInf(x: anytype) bool

Exemplo 1: Cálculos Científicos

const std = @import("std");
const math = std.math;

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Constantes
    try stdout.print("Pi:  {d:.10}\n", .{math.pi});
    try stdout.print("E:   {d:.10}\n", .{math.e});
    try stdout.print("Tau: {d:.10}\n", .{math.tau});

    // Trigonometria
    const angulo: f64 = math.pi / 4.0; // 45 graus
    try stdout.print("\nÂngulo: {d:.4} rad ({d:.0} graus)\n", .{
        angulo,
        angulo * 180.0 / math.pi,
    });
    try stdout.print("sin: {d:.6}\n", .{math.sin(angulo)});
    try stdout.print("cos: {d:.6}\n", .{math.cos(angulo)});
    try stdout.print("tan: {d:.6}\n", .{math.tan(angulo)});

    // Exponencial e logaritmo
    try stdout.print("\nexp(1):   {d:.6}\n", .{math.exp(@as(f64, 1.0))});
    try stdout.print("ln(e):    {d:.6}\n", .{math.log(math.e)});
    try stdout.print("log2(8):  {d:.6}\n", .{math.log2(@as(f64, 8.0))});
    try stdout.print("log10(100): {d:.6}\n", .{math.log10(@as(f64, 100.0))});
    try stdout.print("sqrt(2):  {d:.6}\n", .{math.sqrt(@as(f64, 2.0))});

    // Potência
    try stdout.print("2^10: {d:.0}\n", .{math.pow(f64, 2.0, 10.0)});
}

Exemplo 2: Aritmética Segura contra Overflow

const std = @import("std");
const math = std.math;

fn somaSegura(a: i32, b: i32) !i32 {
    return math.add(i32, a, b);
}

fn fatorial(n: u64) !u64 {
    var resultado: u64 = 1;
    var i: u64 = 2;
    while (i <= n) : (i += 1) {
        resultado = try math.mul(u64, resultado, i);
    }
    return resultado;
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // Soma segura
    const a = try somaSegura(100, 200);
    try stdout.print("100 + 200 = {d}\n", .{a});

    // Detecção de overflow
    if (somaSegura(math.maxInt(i32), 1)) |_| {
        try stdout.writeAll("Sem overflow (inesperado)\n");
    } else |_| {
        try stdout.writeAll("Overflow detectado em maxInt(i32) + 1\n");
    }

    // Fatorial com detecção de overflow
    try stdout.writeAll("\nFatoriais:\n");
    for (1..25) |n| {
        if (fatorial(n)) |resultado| {
            try stdout.print("  {d:>2}! = {d}\n", .{ n, resultado });
        } else |_| {
            try stdout.print("  {d:>2}! = overflow!\n", .{n});
            break;
        }
    }

    // Limites de tipos
    try stdout.print("\nLimites:\n", .{});
    try stdout.print("  i8:  [{d}, {d}]\n", .{ math.minInt(i8), math.maxInt(i8) });
    try stdout.print("  u8:  [0, {d}]\n", .{math.maxInt(u8)});
    try stdout.print("  i32: [{d}, {d}]\n", .{ math.minInt(i32), math.maxInt(i32) });
    try stdout.print("  u64: [0, {d}]\n", .{math.maxInt(u64)});
}

Exemplo 3: Geometria e Vetores

const std = @import("std");
const math = std.math;

const Vec2 = struct {
    x: f64,
    y: f64,

    fn magnitude(self: Vec2) f64 {
        return math.sqrt(self.x * self.x + self.y * self.y);
    }

    fn normalizar(self: Vec2) Vec2 {
        const mag = self.magnitude();
        if (mag == 0) return self;
        return .{ .x = self.x / mag, .y = self.y / mag };
    }

    fn distancia(a: Vec2, b: Vec2) f64 {
        const dx = b.x - a.x;
        const dy = b.y - a.y;
        return math.sqrt(dx * dx + dy * dy);
    }

    fn angulo(a: Vec2, b: Vec2) f64 {
        return math.atan2(b.y - a.y, b.x - a.x);
    }

    fn rotacionar(self: Vec2, theta: f64) Vec2 {
        const c = math.cos(theta);
        const s = math.sin(theta);
        return .{
            .x = self.x * c - self.y * s,
            .y = self.x * s + self.y * c,
        };
    }
};

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const a = Vec2{ .x = 3.0, .y = 4.0 };
    const b = Vec2{ .x = 7.0, .y = 1.0 };

    try stdout.print("Vetor A: ({d:.2}, {d:.2})\n", .{ a.x, a.y });
    try stdout.print("Magnitude: {d:.4}\n", .{a.magnitude()});

    const norm = a.normalizar();
    try stdout.print("Normalizado: ({d:.4}, {d:.4})\n", .{ norm.x, norm.y });
    try stdout.print("Mag normalizado: {d:.4}\n", .{norm.magnitude()});

    try stdout.print("\nDistância A-B: {d:.4}\n", .{Vec2.distancia(a, b)});

    const angulo_graus = Vec2.angulo(a, b) * 180.0 / math.pi;
    try stdout.print("Ângulo A->B: {d:.2} graus\n", .{angulo_graus});

    // Rotaciona 90 graus
    const rotacionado = a.rotacionar(math.pi / 2.0);
    try stdout.print("A rotacionado 90°: ({d:.2}, {d:.2})\n", .{
        rotacionado.x, rotacionado.y,
    });

    // Clamp
    try stdout.print("\nClamp:\n", .{});
    for ([_]f64{ -5.0, 0.0, 3.0, 7.0, 15.0 }) |v| {
        try stdout.print("  clamp({d:.0}, 0, 10) = {d:.0}\n", .{
            v, math.clamp(v, 0.0, 10.0),
        });
    }
}

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

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