---
title: "Tipos Numéricos em Rust: i32, u64, f64 e Mais"
url: "https://rustlang.com.br/stdlib/tipos-numericos/"
markdown_url: "https://rustlang.com.br/stdlib/tipos-numericos.MD"
description: "Guia completo dos tipos numéricos em Rust: inteiros i8-i128, u8-u128, isize, usize, floats f32 e f64, aritmética segura e conversão com as e TryFrom."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Tipos Numéricos em Rust: i32, u64, f64 e Mais

Guia completo dos tipos numéricos em Rust: inteiros i8-i128, u8-u128, isize, usize, floats f32 e f64, aritmética segura e conversão com as e TryFrom.


Os **tipos numéricos** são os tipos mais fundamentais em Rust. A linguagem oferece inteiros com e sem sinal em tamanhos de 8 a 128 bits, dois tipos de ponto flutuante, e um conjunto robusto de operações aritméticas que previnem erros comuns como overflow silencioso. Entender esses tipos é essencial para escrever código Rust correto e eficiente.

## Tabela de Tipos Inteiros

| Tipo | Tamanho | Faixa de Valores | Uso Típico |
|---|---|---|---|
| `i8` | 8 bits | -128 a 127 | Dados compactos, C FFI |
| `i16` | 16 bits | -32.768 a 32.767 | Áudio, C FFI |
| `i32` | 32 bits | -2.147.483.648 a 2.147.483.647 | **Padrão para inteiros** |
| `i64` | 64 bits | -9,2 x 10^18 a 9,2 x 10^18 | Timestamps, IDs grandes |
| `i128` | 128 bits | -1,7 x 10^38 a 1,7 x 10^38 | Criptografia, cálculos grandes |
| `u8` | 8 bits | 0 a 255 | Bytes, pixels, ASCII |
| `u16` | 16 bits | 0 a 65.535 | Portas de rede, Unicode |
| `u32` | 32 bits | 0 a 4.294.967.295 | Contadores, IDs |
| `u64` | 64 bits | 0 a 1,8 x 10^19 | Hashes, tamanhos de arquivo |
| `u128` | 128 bits | 0 a 3,4 x 10^38 | UUIDs, criptografia |
| `isize` | ptr size | Depende da plataforma | Índices de ponteiro |
| `usize` | ptr size | Depende da plataforma | **Índices, tamanhos** |

## Tabela de Tipos de Ponto Flutuante

| Tipo | Tamanho | Precisão | Faixa | Uso Típico |
|---|---|---|---|---|
| `f32` | 32 bits | ~7 dígitos | +/-3,4 x 10^38 | Gráficos, GPU, quando memória importa |
| `f64` | 64 bits | ~15 dígitos | +/-1,8 x 10^308 | **Padrão**, cálculos científicos |

## Literais Numéricos

```rust
fn main() {
    // Literais inteiros
    let decimal = 1_000_000;         // separador _ para legibilidade
    let hexadecimal = 0xFF;          // 255
    let octal = 0o77;                // 63
    let binario = 0b1111_0000;       // 240
    let byte = b'A';                 // u8, valor 65

    // Sufixo de tipo
    let x = 42i32;                   // i32
    let y = 100u64;                  // u64
    let z = 3.14f32;                 // f32

    // Literais de ponto flutuante
    let pi = 3.14159265;             // f64 por padrão
    let avogadro = 6.022e23;         // notação científica
    let pequeno = 1.6e-19_f64;      // com sufixo

    // Tipo padrão
    let inteiro = 42;                // i32 (padrão)
    let flutuante = 3.14;            // f64 (padrão)

    println!("decimal: {}", decimal);
    println!("hex: {:#X}", hexadecimal);
    println!("oct: {:#o}", octal);
    println!("bin: {:#010b}", binario);
    println!("byte: {}", byte);
    println!("avogadro: {:.3e}", avogadro);
}
```

## Exemplos Práticos

### 1. Limites e Constantes dos Tipos

```rust
fn main() {
    // Constantes MIN e MAX
    println!("i8:    {} a {}", i8::MIN, i8::MAX);
    println!("i16:   {} a {}", i16::MIN, i16::MAX);
    println!("i32:   {} a {}", i32::MIN, i32::MAX);
    println!("i64:   {} a {}", i64::MIN, i64::MAX);
    println!("i128:  {} a {}", i128::MIN, i128::MAX);
    println!();
    println!("u8:    {} a {}", u8::MIN, u8::MAX);
    println!("u16:   {} a {}", u16::MIN, u16::MAX);
    println!("u32:   {} a {}", u32::MIN, u32::MAX);
    println!("u64:   {} a {}", u64::MIN, u64::MAX);
    println!();
    println!("usize: {} a {} ({} bits)", usize::MIN, usize::MAX, usize::BITS);
    println!("isize: {} a {} ({} bits)", isize::MIN, isize::MAX, isize::BITS);
    println!();
    println!("f32 epsilon: {}", f32::EPSILON);
    println!("f64 epsilon: {}", f64::EPSILON);
    println!("f64 infinity: {}", f64::INFINITY);
    println!("f64 NaN: {}", f64::NAN);
    println!("f64 pi: {}", std::f64::consts::PI);
    println!("f64 e: {}", std::f64::consts::E);

    // Tamanho em bytes
    println!("\nTamanhos:");
    println!("  i32: {} bytes", std::mem::size_of::<i32>());
    println!("  u64: {} bytes", std::mem::size_of::<u64>());
    println!("  f64: {} bytes", std::mem::size_of::<f64>());
    println!("  usize: {} bytes", std::mem::size_of::<usize>());
}
```

### 2. Aritmética Segura — checked, wrapping, saturating, overflowing

```rust
fn main() {
    let a: u8 = 250;
    let b: u8 = 10;

    // Em modo debug, overflow causa panic!
    // let resultado = a + b; // PANIC em debug!

    // checked: retorna None em overflow
    let checked = a.checked_add(b);
    println!("checked_add: {:?}", checked); // None

    let checked_ok = 100u8.checked_add(50);
    println!("checked_add (ok): {:?}", checked_ok); // Some(150)

    // wrapping: faz wrap around (como C)
    let wrapped = a.wrapping_add(b);
    println!("wrapping_add: {}", wrapped); // 4 (256 + 4 = 260, mod 256 = 4)

    // saturating: para no MAX ou MIN
    let saturated = a.saturating_add(b);
    println!("saturating_add: {}", saturated); // 255 (u8::MAX)

    let saturated_sub = 5u8.saturating_sub(10);
    println!("saturating_sub: {}", saturated_sub); // 0 (u8::MIN)

    // overflowing: retorna (resultado, overflow?)
    let (resultado, overflow) = a.overflowing_add(b);
    println!("overflowing_add: {} (overflow: {})", resultado, overflow);
    // 4 (overflow: true)

    // Multiplicação segura
    let grande = 1_000_000_000i32;
    match grande.checked_mul(3) {
        Some(r) => println!("Multiplicação ok: {}", r),    // 3_000_000_000 > i32::MAX
        None => println!("Overflow na multiplicação!"),
    }

    // Potência segura
    let base: u64 = 2;
    println!("2^10 = {}", base.pow(10));         // 1024
    println!("2^63 checked = {:?}", base.checked_pow(63)); // Some(...)
    println!("2^64 checked = {:?}", base.checked_pow(64)); // None (overflow)
}
```

### 3. Conversão entre Tipos — as, From, TryFrom

```rust
use std::convert::TryFrom;

fn main() {
    // 'as' — conversão explícita (pode perder dados!)
    let grande: i64 = 1_000_000;
    let pequeno: i32 = grande as i32; // OK, cabe em i32
    println!("i64 -> i32: {}", pequeno);

    let muito_grande: i64 = 5_000_000_000;
    let truncado: i32 = muito_grande as i32; // PERDA DE DADOS!
    println!("5 bilhões as i32: {} (TRUNCADO!)", truncado);

    // float -> int trunca a parte decimal
    let pi = 3.99;
    let inteiro = pi as i32; // 3, não 4!
    println!("3.99 as i32: {} (truncado, não arredondado)", inteiro);

    // int -> float pode perder precisão
    let grande_int: i64 = (1i64 << 53) + 1;
    let como_f64 = grande_int as f64;
    println!("2^53 + 1 como f64: {} (pode perder precisão)", como_f64);

    // From — conversão segura (nunca perde dados)
    let x: i32 = 42;
    let y: i64 = i64::from(x);       // i32 -> i64 sempre cabe
    let z: f64 = f64::from(x);       // i32 -> f64 sempre cabe
    println!("From: i32({}) -> i64({}) -> f64({})", x, y, z);

    let byte: u8 = 200;
    let maior: u32 = u32::from(byte); // u8 -> u32 sempre cabe
    println!("u8({}) -> u32({})", byte, maior);

    // TryFrom — conversão que pode falhar
    let valor: i64 = 300;
    match u8::try_from(valor) {
        Ok(v) => println!("i64({}) -> u8({}) ok!", valor, v),
        Err(e) => println!("i64({}) -> u8 falhou: {}", valor, e),
    }

    let ok: i64 = 100;
    let resultado = u8::try_from(ok);
    println!("i64({}) -> u8 = {:?}", ok, resultado); // Ok(100)

    // Conversão de string para número
    let numero: i32 = "42".parse().unwrap();
    let flutuante: f64 = "3.14".parse().unwrap();
    println!("parse: {} e {}", numero, flutuante);

    // Conversão com tratamento de erro
    match "abc".parse::<i32>() {
        Ok(n) => println!("Convertido: {}", n),
        Err(e) => println!("Erro ao converter 'abc': {}", e),
    }
}
```

### 4. Métodos Úteis dos Tipos Numéricos

```rust
fn main() {
    // Métodos de inteiros
    let n: i32 = -42;
    println!("abs: {}", n.abs());           // 42
    println!("signum: {}", n.signum());     // -1
    println!("pow: {}", 2i32.pow(10));      // 1024
    println!("min: {}", 10i32.min(20));     // 10
    println!("max: {}", 10i32.max(20));     // 20
    println!("clamp: {}", 150i32.clamp(0, 100)); // 100

    // Contagem de bits
    let bits: u32 = 0b1010_1100;
    println!("\nBits de {:08b}:", bits);
    println!("  count_ones: {}", bits.count_ones());     // 4
    println!("  count_zeros: {}", bits.count_zeros());   // 28
    println!("  leading_zeros: {}", bits.leading_zeros()); // 24
    println!("  trailing_zeros: {}", bits.trailing_zeros()); // 2

    // Métodos de ponto flutuante
    let x: f64 = 2.7;
    println!("\nf64 métodos:");
    println!("  floor: {}", x.floor());     // 2.0
    println!("  ceil: {}", x.ceil());       // 3.0
    println!("  round: {}", x.round());     // 3.0
    println!("  trunc: {}", x.trunc());     // 2.0
    println!("  fract: {}", x.fract());     // 0.7
    println!("  sqrt: {}", x.sqrt());       // 1.643...
    println!("  cbrt: {}", x.cbrt());       // 1.392...
    println!("  ln: {}", x.ln());           // 0.993...
    println!("  log2: {}", x.log2());       // 1.432...
    println!("  log10: {}", x.log10());     // 0.431...
    println!("  sin: {}", x.sin());
    println!("  cos: {}", x.cos());

    // Verificações de ponto flutuante
    let inf = f64::INFINITY;
    let nan = f64::NAN;
    println!("\nVerificações:");
    println!("  INFINITY.is_infinite: {}", inf.is_infinite());   // true
    println!("  INFINITY.is_finite: {}", inf.is_finite());       // false
    println!("  NAN.is_nan: {}", nan.is_nan());                  // true
    println!("  3.14.is_normal: {}", 3.14f64.is_normal());       // true
    println!("  0.0.is_normal: {}", 0.0f64.is_normal());         // false

    // CUIDADO: NaN != NaN
    println!("  NaN == NaN: {}", nan == nan); // false!
}
```

### 5. Padrões Comuns e Boas Práticas

```rust
fn main() {
    // Evitar overflow com tipos maiores
    let fatorial_10: u64 = (1..=10u64).product();
    println!("10! = {}", fatorial_10); // 3628800

    // Formatar números
    let valor = 1_234_567.89;
    println!("Padrão: {}", valor);
    println!("2 decimais: {:.2}", valor);
    println!("Científico: {:.3e}", valor);
    println!("Hexadecimal: {:X}", 255);
    println!("Binário: {:08b}", 42);
    println!("Octal: {:o}", 255);
    println!("Com sinal: {:+}", 42);
    println!("Padding: {:>10}", 42);
    println!("Zero-pad: {:010}", 42);

    // Comparar floats com epsilon
    let a = 0.1 + 0.2;
    let b = 0.3;
    println!("\n0.1 + 0.2 == 0.3? {}", a == b);     // false!
    println!("0.1 + 0.2 = {:.20}", a);

    // Comparação correta com epsilon
    let epsilon = 1e-10;
    println!("Aproximadamente igual? {}", (a - b).abs() < epsilon); // true

    // Usar usize para índices
    let dados = vec![10, 20, 30, 40, 50];
    let indice: usize = 3; // índices são sempre usize
    println!("\ndados[{}] = {}", indice, dados[indice]);

    // Converter entre isize/usize cuidadosamente
    let tamanho: usize = dados.len();
    let diferenca: isize = 2 - tamanho as isize; // pode ser negativo
    println!("Diferença: {}", diferenca);

    // Prevenir divisão por zero
    fn dividir_seguro(a: f64, b: f64) -> Option<f64> {
        if b == 0.0 {
            None
        } else {
            Some(a / b)
        }
    }

    match dividir_seguro(10.0, 3.0) {
        Some(r) => println!("10 / 3 = {:.4}", r),
        None => println!("Divisão por zero!"),
    }
}
```

## Características de Desempenho

| Operação | Inteiros | Floats |
|---|---|---|
| Adição/Subtração | O(1), 1 ciclo | O(1), 1-3 ciclos |
| Multiplicação | O(1), 1-3 ciclos | O(1), 3-5 ciclos |
| Divisão | O(1), 20-40 ciclos | O(1), 10-20 ciclos |
| Comparação | O(1), 1 ciclo | O(1), 1-3 ciclos |
| Conversão int->float | O(1), 3-5 ciclos | - |
| checked_add vs add | +1-2 ciclos overhead | - |
| sqrt/sin/cos/ln | - | O(1), 10-30 ciclos |

**Tamanho e alinhamento:** Os tipos numéricos são alinhados ao seu próprio tamanho. Um `i32` ocupa 4 bytes com alinhamento de 4 bytes. Um `i128` ocupa 16 bytes com alinhamento de 16 bytes em muitas plataformas.

**Escolha de tipo:**
- Use `i32` como padrão para inteiros.
- Use `u8` para bytes e dados binários.
- Use `usize` para índices e tamanhos.
- Use `f64` como padrão para ponto flutuante.
- Use `f32` apenas quando memória/bandwidth importa (GPU, grandes arrays).

## Tabela Comparativa: Segurança Aritmética

| Método | Overflow Behavior | Tipo de Retorno | Quando Usar |
|---|---|---|---|
| `+` (operador) | Panic em debug, wrap em release | `T` | Quando overflow é um bug |
| `checked_add` | Retorna `None` | `Option<T>` | Quando overflow é possível |
| `wrapping_add` | Wrap around | `T` | Hashing, criptografia |
| `saturating_add` | Para no MAX/MIN | `T` | Áudio, processamento de sinais |
| `overflowing_add` | Wrap + flag | `(T, bool)` | Quando precisa saber se houve overflow |

## Veja Também

- [Converter String para Número](/receitas/converter-string-numero/) --- parse, from_str e tratamento de erros
- [Variáveis, Tipos e Funções](/tutoriais/variaveis-tipos-funcoes/) --- fundamentos de tipos e variáveis
- [Tuplas em Rust](/stdlib/tuplas/) --- agrupando valores numéricos
- [Arrays em Rust](/stdlib/arrays/) --- arrays de tipos numéricos
- [Ranges em Rust](/stdlib/ranges/) --- faixas numéricas para iteração
- [Formatar Strings em Rust](/receitas/formatar-strings/) --- formatação de números
- [Tratamento de Erros](/tutoriais/tratamento-de-erros/) --- lidando com conversões que podem falhar
