Java Math

Os operadores aritméticos fazem as quatro operações e o resto. Para todo o resto da calculadora (raiz quadrada, potência, arredondar, maior e menor, valor absoluto) o Java traz a classe Math ("matemática"), uma caixa de ferramentas pronta, que você usa sem instalar nem importar nada.

Você vai aprender
  • Como chamar um método de Math e o que ele devolve.
  • Math.max, min, abs, sqrt, pow, e as constantes Math.PI e Math.E.
  • Arredondar: round, floor, ceil, e por que Math.round(2.5) dá 3 mas Math.round(-2.5) dá -2.
  • Arredondar com casas decimais (e a armadilha do double).
  • Math.random, floorDiv e floorMod, e o que fazer com números negativos.
  • Os erros de tipo mais comuns (possible lossy conversion).

A ideia: uma calculadora científica embutida

Pense na tecla de raiz quadrada de uma calculadora: você digita 64, aperta √ e aparece 8. Em Java, cada "tecla" é um método da classe Math. Você chama assim:

Math
O nome da classe, com M maiúsculo. Ela faz parte do pacote java.lang, que o Java já carrega em todo programa; por isso não precisa de import (veja Pacotes e import).
.sqrt
O método (a "tecla"): square root, raiz quadrada.
(64)
O valor que você entrega, chamado argumento. Alguns métodos pedem dois (Math.pow(2, 10)), outros nenhum (Math.random()).
resultado
O método devolve um valor, que você imprime, guarda numa variável ou usa numa conta: double r = Math.sqrt(64);.

Repare que você chama o método na própria classe (Math.sqrt), e não numa variável, como fazia com Strings (nome.length()). Métodos assim se chamam estáticos (static); o assunto tem aula própria em static.


Maior, menor e valor absoluto: max, min, abs

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.max(3, 7));
        System.out.println(Math.min(3, 7));
        System.out.println(Math.max(2.5, 1.5));
        System.out.println(Math.max(4, 2.5));
        System.out.println(Math.abs(-10));
        System.out.println(Math.abs(-3.7));
        System.out.println(Math.abs(5));
        int nota1 = 7, nota2 = 9, nota3 = 6;
        System.out.println(Math.max(nota1, Math.max(nota2, nota3)));
    }
}
$ java Main.java
7       « o maior de 3 e 7
3       « o menor
2.5
4.0     « int com double: o resultado é double, por isso 4.0
10      « abs = valor absoluto: tira o sinal de menos
3.7
5       « positivo continua igual
9       « o maior de três números: um max dentro do outro
Math.max(a, b) / Math.min(a, b)
O maior / o menor de dois números. O tipo do resultado acompanha os argumentos: dois int dão int; se um for double, dá double.
Math.abs(x)
Absolute value: a "distância até o zero", sempre positiva. Útil para diferenças: Math.abs(a - b) é a diferença entre a e b, não importa qual é maior.
Math.max(nota1, Math.max(nota2, nota3))
Para três números, chame um max dentro do outro. O de dentro roda primeiro (o maior entre nota2 e nota3) e o resultado vira argumento do de fora.

Missão: mostre a maior e a menor das três notas usando Math.max e Math.min. A saída deve ser Maior: 9.0 e Menor: 6.0.

public class Main {
    public static void main(String[] args) {
        double nota1 = 7.5;
        double nota2 = 9.0;
        double nota3 = 6.0;
        // calcule a maior e a menor
    }
}
public class Main {
    public static void main(String[] args) {
        double nota1 = 7.5;
        double nota2 = 9.0;
        double nota3 = 6.0;
        double maior = Math.max(nota1, Math.max(nota2, nota3));
        double menor = Math.min(nota1, Math.min(nota2, nota3));
        System.out.println("Maior: " + maior);
        System.out.println("Menor: " + menor);
    }
}

Raiz e potência: sqrt e pow

Java não tem um operador de potência (o ^ existe, mas é outra coisa, uma operação com bits). Para "2 elevado a 10", use Math.pow(2, 10) (power, potência).

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.sqrt(64));
        System.out.println(Math.sqrt(2));
        System.out.println(Math.pow(2, 10));
        System.out.println(Math.pow(9, 0.5));
        System.out.println(Math.pow(10, -2));
        System.out.println(Math.cbrt(27));
        System.out.println(Math.sqrt(-1));
        int kb = (int) Math.pow(2, 10);
        System.out.println(kb);
    }
}
$ java Main.java
8.0                   « raiz quadrada de 64
1.4142135623730951    « raiz de 2, com toda a precisão do double
1024.0                « 2 elevado a 10
3.0                   « elevar a 0.5 é tirar a raiz quadrada
0.01                  « 10 elevado a -2 = 1/100
3.0                   « cbrt = raiz cúbica (cube root)
NaN                   « raiz de número negativo: "não é um número"
1024                  « convertido para int

Três coisas para guardar:

  • sqrt e pow sempre devolvem double, mesmo quando a conta dá um número inteiro (8.0, 1024.0). Para guardar num int, converta com (int) (veja Conversão de Tipos).
  • NaN (Not a Number, "não é um número") é o jeito do double dizer "essa conta não tem resposta". Não é um erro: o programa continua, mas qualquer conta com NaN dá NaN. Veja double e float.
  • Para elevar ao quadrado, x * x é mais simples e exato que Math.pow(x, 2); o pow vale a pena para expoentes maiores ou quebrados.

Constantes: Math.PI e Math.E

Math.PI é o π (3,14159…), com a maior precisão que um double guarda. Math.E é o número de Euler (2,71828…), base dos logaritmos naturais. Elas não têm parênteses: não são métodos, são constantes (valores fixos, escritos em maiúsculas).

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.PI);
        System.out.println(Math.E);
        double raio = 3;
        double area = Math.PI * Math.pow(raio, 2);
        System.out.println(area);
        System.out.println(Math.round(area * 100) / 100.0);
        System.out.println(Math.hypot(3, 4));
    }
}
$ java Main.java
3.141592653589793
2.718281828459045
28.274333882308138     « área do círculo de raio 3: π × r²
28.27                  « a mesma área com 2 casas (explicado logo abaixo)
5.0                    « hypot: a hipotenusa de um triângulo de lados 3 e 4

Arredondar: round, floor, ceil

Há três jeitos de transformar um número quebrado num número "redondo":

MétodoNomeFazDevolve
Math.round(x)round, arredondarVai para o inteiro mais próximo; no empate (.5), para cimalong (inteiro)
Math.floor(x)floor, chãoSempre para baixo (o inteiro menor ou igual)double
Math.ceil(x)ceiling, tetoSempre para cima (o inteiro maior ou igual)double

Pense numa escada: floor desce para o degrau de baixo, ceil sobe para o de cima e round vai para o degrau mais perto. Agora a prova, incluindo os negativos:

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.round(2.4));
        System.out.println(Math.round(2.5));
        System.out.println(Math.round(2.6));
        System.out.println(Math.round(-2.4));
        System.out.println(Math.round(-2.5));
        System.out.println(Math.round(-2.6));
        System.out.println(Math.floor(2.7));
        System.out.println(Math.ceil(2.1));
        System.out.println(Math.floor(-2.5));
        System.out.println(Math.ceil(-2.5));
        System.out.println(Math.rint(2.5));
        System.out.println(Math.rint(3.5));
    }
}
$ java Main.java
2       « 2.4 → mais perto do 2
3       « 2.5 → empate: vai para 3
3
-2
-2      « -2.5 → empate: vai para -2 (e não -3!)
-3
2.0     « floor: para baixo
3.0     « ceil: para cima, mesmo com .1
-3.0    « floor de -2.5: "para baixo" nos negativos é -3
-2.0    « ceil de -2.5: "para cima" é -2
2.0     « rint: no empate, vai para o PAR mais próximo
4.0

Por que Math.round(-2.5) dá -2?

Na escola, aprendemos "no 5, arredonda para cima", e para positivos o Java faz exatamente isso. A surpresa é que "para cima" quer dizer na direção do maior número, e nos negativos o maior é o que está mais perto do zero: -2 é maior que -3. Na reta numérica:

  -3 ─── -2.5 ─── -2 ─── … ─── 2 ─── 2.5 ─── 3
          └──────→ "para cima" ←      └──────→ "para cima"

Por dentro, o Math.round(x) funciona como Math.floor(x + 0.5): 2.5 + 0.5 = 3.0 → chão = 3; -2.5 + 0.5 = -2.0 → chão = -2. Se você precisa que o empate se afaste do zero (-2.5 → -3) ou siga outra regra (como a dos bancos), use BigDecimal, que permite escolher o modo de arredondamento (veja BigDecimal e Dinheiro). O Math.rint usa a regra "do par" (2.5 → 2, 3.5 → 4), que evita puxar sempre para o mesmo lado.

round devolve long; floor e ceil devolvem double

Por isso Math.round(2.5) aparece como 3 e Math.floor(2.7) como 2.0. E por isso int x = Math.round(2.5); não compila (veja "Quando dá errado"). Cortar a parte decimal com (int) é ainda outra regra: (int) 2.9 é 2 e (int) -2.9 é -2 (corta em direção ao zero).


Arredondar com casas decimais

O Math.round só arredonda para inteiro. Para 2 casas, o truque é: multiplique por 100, arredonde, divida por 100.0.

public class Main {
    public static void main(String[] args) {
        double preco = 3.14159;
        System.out.println(Math.round(preco * 100) / 100.0);
        System.out.println(Math.round(preco * 100) / 100);
        System.out.println(Math.round(preco * 10) / 10.0);
        System.out.println(Math.round(preco * 1000) / 1000.0);
        System.out.println(String.format("%.2f", preco));
    }
}
$ java Main.java
3.14     « 314.159 → round → 314 → / 100.0 → 3.14
3        « dividido por 100 (inteiro): divisão inteira, perdeu tudo!
3.1      « 1 casa: × 10 e / 10.0
3.142    « 3 casas: × 1000 e / 1000.0
3,14     « String.format: vira TEXTO, com a vírgula do pt_BR
preco * 100
Empurra a vírgula duas casas: 314.159.
Math.round(…)
Arredonda para o inteiro mais próximo: 314 (um long).
/ 100.0
Puxa a vírgula de volta: 3.14. O .0 é essencial: 314 / 100 é divisão de inteiros e dá 3 (veja Operadores Aritméticos).

Se o objetivo é só mostrar o número com 2 casas, String.format("%.2f", x) ou printf são melhores (veja Formatar Texto): o resultado é um texto, pronto para a tela, com vírgula no Brasil.

A armadilha do double

O double guarda os números em binário, e muitos decimais "redondos" para nós não têm representação exata (veja double e float). Às vezes isso aparece no arredondamento:

$ jshell
|  Welcome to JShell -- Version 25.0.4.1
|  For an introduction type: /help intro

jshell> 1.005 * 100
$1 ==> 100.49999999999999

jshell> Math.round(1.005 * 100) / 100.0
$2 ==> 1.0

jshell> String.format("%.2f", 1.005)
$3 ==> "1,01"

jshell> /exit
|  Goodbye

Esperávamos 1.01, mas 1.005 * 100 deu 100.49999999999999, que arredonda para 100. Para contas com dinheiro, onde cada centavo importa, use BigDecimal. Para mostrar na tela, String.format.


Números aleatórios: Math.random()

Math.random() devolve um double "sorteado" entre 0.0 (pode sair) e 1.0 (nunca sai). Cada execução dá valores diferentes:

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.random());
        System.out.println(Math.random());
    }
}
$ java Main.java
0.5897360548361562
0.08252130589441309      « na sua vez, serão outros números

Transformar isso num dado de 1 a 6, num sorteio ou numa senha é assunto da próxima aula: Números Aleatórios.


Divisão com negativos: floorDiv e floorMod

A divisão inteira / do Java corta a parte decimal (em direção ao zero), e o resto % fica com o sinal do primeiro número. Com positivos, tudo bem. Com negativos, o resultado pode não ser o que você quer. Math.floorDiv arredonda a divisão para baixo, e Math.floorMod dá um resto que é sempre positivo quando o divisor é positivo.

public class Main {
    public static void main(String[] args) {
        System.out.println(-7 / 2);
        System.out.println(Math.floorDiv(-7, 2));
        System.out.println(-7 % 2);
        System.out.println(Math.floorMod(-7, 2));
        System.out.println(7 / 2 + " " + Math.floorDiv(7, 2));
        int hora = 2;
        System.out.println((hora - 5) % 24);
        System.out.println(Math.floorMod(hora - 5, 24));
    }
}
$ java Main.java
-3       « -3.5 cortado em direção ao zero
-4       « -3.5 arredondado para baixo
-1       « resto com o sinal do -7
1        « floorMod: resto sempre entre 0 e 1
3 3      « com positivos, os dois dão o mesmo
-3       « "5 horas antes das 2h" com %: -3 horas?!
21       « com floorMod: 21h, a resposta certa

O exemplo do relógio mostra onde isso importa: contas que "dão a volta" (horas, dias da semana, posições num círculo). São 2h da manhã; cinco horas antes eram 21h do dia anterior. O % responde -3, que não é hora nenhuma; o floorMod responde 21. Regra prática: quando o número da esquerda pode ser negativo e você quer "dar a volta", use floorMod.


Outros métodos úteis

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.signum(-8.0));
        System.out.println(Math.clamp(120, 0, 100));
        System.out.println(Math.clamp(-5, 0, 100));
        System.out.println(Math.clamp(42, 0, 100));
        System.out.println(Math.log10(1000));
        System.out.println(Math.sin(Math.PI / 2));
    }
}
$ java Main.java
-1.0     « signum: o sinal (-1, 0 ou 1)
100      « clamp(120, 0, 100): prende entre 0 e 100
0        « clamp(-5, 0, 100)
42       « clamp(42, 0, 100): já estava dentro, fica igual
3.0      « log10(1000): 10 elevado a 3 dá 1000
1.0      « seno de 90 graus (π/2 radianos)

Math.clamp(valor, mínimo, máximo) Java 21+ "prende" um valor numa faixa: abaixo do mínimo vira o mínimo, acima do máximo vira o máximo. Ótimo para porcentagens, volume, notas de 0 a 10. Antes do Java 21, escreva Math.max(0, Math.min(valor, 100)).

MétodoFazExemplo → resultado
Math.cbrt(x)Raiz cúbicaMath.cbrt(27) → 3.0
Math.hypot(a, b)√(a² + b²), a hipotenusaMath.hypot(3, 4) → 5.0
Math.signum(x)Sinal: -1.0, 0.0 ou 1.0Math.signum(-8.0) → -1.0
Math.clamp(v, min, max)Prende v na faixa (Java 21+)Math.clamp(120, 0, 100) → 100
Math.log(x), Math.log10(x)Logaritmo natural / na base 10Math.log10(1000) → 3.0
Math.sin, cos, tanTrigonometria (ângulos em radianos)Math.sin(Math.PI / 2) → 1.0
Math.toRadians(g)Graus para radianosMath.toRadians(180) → π
Math.addExact(a, b)Soma que avisa se estourar o intveja abaixo

Contas que avisam o estouro: addExact

Você viu em int, long, short, byte que um int que passa do limite "dá a volta" sem avisar. As versões Exact (addExact, subtractExact, multiplyExact) fazem a mesma conta, mas lançam uma exceção em vez de dar um resultado errado:

public class Main {
    public static void main(String[] args) {
        int grande = Integer.MAX_VALUE;
        System.out.println(grande + 1);
        System.out.println(Math.abs(Integer.MIN_VALUE));
        System.out.println(Math.addExact(grande, 1));
    }
}
$ java Main.java
-2147483648       « o + estourou e deu a volta, sem aviso
-2147483648       « nem o abs escapa: o positivo não cabe no int
Exception in thread "main" java.lang.ArithmeticException: integer overflow
	at java.base/java.lang.Math.addExact(Math.java:915)
	at Main.main(Main.java:6)

integer overflow = "estouro de inteiro". Melhor um programa que para com uma mensagem clara do que um que segue com um número errado.


Quando dá errado

error: incompatible types: possible lossy conversion from double to int

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        int raiz = Math.sqrt(16);
        System.out.println(raiz);
    }
}
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from double to int
        int raiz = Math.sqrt(16);
                            ^
1 error

O que aconteceu: Math.sqrt devolve double, e guardar um double num int pode perder a parte decimal ("possível conversão com perda"). O javac não faz isso escondido. O mesmo vale para pow, floor e ceil.

Como resolver: guarde num double (double raiz = Math.sqrt(16);) ou converta de propósito: int raiz = (int) Math.sqrt(16);.

error: incompatible types: possible lossy conversion from long to int

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        int arredondado = Math.round(2.5);
        System.out.println(arredondado);
    }
}
$ javac Main.java
Main.java:3: error: incompatible types: possible lossy conversion from long to int
        int arredondado = Math.round(2.5);
                                    ^
1 error

O que aconteceu: Math.round de um double devolve long. (De um float, como Math.round(2.5f), devolve int.)

Como resolver: long arredondado = Math.round(2.5); ou int arredondado = (int) Math.round(2.5);.

error: cannot find symbol … symbol: variable math

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        System.out.println(math.max(1, 2));
    }
}
$ javac Main.java
Main.java:3: error: cannot find symbol
        System.out.println(math.max(1, 2));
                           ^
  symbol:   variable math
  location: class Main
1 error

O que aconteceu: com m minúsculo, o javac achou que math fosse uma variável sua, e ela não existe.

Como resolver: Math, com M maiúsculo.

error: method pow in class Math cannot be applied to given types;

Este código tem um erro de propósito.

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.pow(2));
    }
}
$ javac Main.java
Main.java:3: error: method pow in class Math cannot be applied to given types;
        System.out.println(Math.pow(2));
                               ^
  required: double,double
  found:    int
  reason: actual and formal argument lists differ in length
1 error

O que aconteceu: "o método pow não pode ser aplicado a esses tipos". O javac mostra o que o método exige (required: double,double, dois números) e o que recebeu (found: int, um só). O motivo: as listas de argumentos têm tamanhos diferentes.

Como resolver: passe a base e o expoente: Math.pow(2, 2).

O arredondamento com casas deu um número inteiro

O que aconteceu: você dividiu por 100 em vez de 100.0, e a divisão foi de inteiros: Math.round(3.14159 * 100) / 100 → 3.

Como resolver: / 100.0.


Referência rápida

MétodoDevolveExemplo → resultado
Math.max(a, b)tipo dos argumentosMath.max(3, 7) → 7
Math.min(a, b)tipo dos argumentosMath.min(3, 7) → 3
Math.abs(x)tipo do argumentoMath.abs(-10) → 10
Math.sqrt(x)doubleMath.sqrt(64) → 8.0
Math.pow(b, e)doubleMath.pow(2, 10) → 1024.0
Math.round(x)longMath.round(-2.5) → -2
Math.floor(x)doubleMath.floor(-2.5) → -3.0
Math.ceil(x)doubleMath.ceil(2.1) → 3.0
Math.random()double em [0, 1)0.5897360548361562
Math.floorDiv(a, b)int/longMath.floorDiv(-7, 2) → -4
Math.floorMod(a, b)int/longMath.floorMod(-7, 2) → 1
Math.PI, Math.Edouble3.141592653589793

Todos os métodos, com mais exemplos, em Referência: Métodos de Math.


Exercícios

Missão final: calcule a área de um círculo de raio 2.5 (π × raio²) e mostre-a arredondada para 2 casas com Math.round. A saída deve ser Área: 19.63.

public class Main {
    public static void main(String[] args) {
        double raio = 2.5;
        // calcule e mostre a área
    }
}
public class Main {
    public static void main(String[] args) {
        double raio = 2.5;
        double area = Math.PI * Math.pow(raio, 2);
        System.out.println("Área: " + Math.round(area * 100) / 100.0);
    }
}

Brinque no JShell: antes de apertar Enter, adivinhe: Math.round(3.5), Math.round(-3.5), Math.floor(-0.1), Math.ceil(-0.9), Math.floorMod(-1, 7).

1. Potência

Complete para calcular 3 elevado a 4:

double r = Math.;

2. Sempre para cima

Uma van leva 8 pessoas. Para levar 30 pessoas, quantas vans? Complete com o método que arredonda para cima:

double vans = Math.(30 / 8.0);

3. O resultado

Quanto vale Math.round(-4.5)?

4. Qual é o tipo do resultado de Math.sqrt(25)?

5. São 1h. Que hora era 3 horas antes? Qual expressão dá a resposta certa (22)?


Resumo

  • Math (M maiúsculo) é uma caixa de métodos estáticos: Math.nome(argumentos). Não precisa de import.
  • max, min, abs mantêm o tipo; sqrt, pow, floor, ceil devolvem double; round devolve long.
  • round vai para o mais próximo e, no empate, "para cima" (para o maior): 2.5 → 3, -2.5 → -2. floor desce, ceil sobe.
  • Duas casas: Math.round(x * 100) / 100.0 (com .0!). Para mostrar, String.format("%.2f", x); para dinheiro, BigDecimal.
  • floorMod dá um resto positivo: use em contas que "dão a volta" com negativos.
  • Math.PI e Math.E são constantes; Math.random() sorteia em [0, 1).