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.
- Como chamar um método de
Mathe o que ele devolve. Math.max,min,abs,sqrt,pow, e as constantesMath.PIeMath.E.- Arredondar:
round,floor,ceil, e por queMath.round(2.5)dá 3 masMath.round(-2.5)dá -2. - Arredondar com casas decimais (e a armadilha do
double). Math.random,floorDivefloorMod, 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 deimport(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
intdãoint; se um fordouble, 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 entreaeb, não importa qual é maior. - Math.max(nota1, Math.max(nota2, nota3))
- Para três números, chame um
maxdentro do outro. O de dentro roda primeiro (o maior entrenota2enota3) 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:
sqrtepowsempre devolvemdouble, mesmo quando a conta dá um número inteiro (8.0,1024.0). Para guardar numint, converta com(int)(veja Conversão de Tipos).NaN(Not a Number, "não é um número") é o jeito dodoubledizer "essa conta não tem resposta". Não é um erro: o programa continua, mas qualquer conta comNaNdáNaN. Veja double e float.- Para elevar ao quadrado,
x * xé mais simples e exato queMath.pow(x, 2); opowvale 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étodo | Nome | Faz | Devolve |
|---|---|---|---|
Math.round(x) | round, arredondar | Vai para o inteiro mais próximo; no empate (.5), para cima | long (inteiro) |
Math.floor(x) | floor, chão | Sempre para baixo (o inteiro menor ou igual) | double |
Math.ceil(x) | ceiling, teto | Sempre 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(umlong). - / 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étodo | Faz | Exemplo → resultado |
|---|---|---|
Math.cbrt(x) | Raiz cúbica | Math.cbrt(27) → 3.0 |
Math.hypot(a, b) | √(a² + b²), a hipotenusa | Math.hypot(3, 4) → 5.0 |
Math.signum(x) | Sinal: -1.0, 0.0 ou 1.0 | Math.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 10 | Math.log10(1000) → 3.0 |
Math.sin, cos, tan | Trigonometria (ângulos em radianos) | Math.sin(Math.PI / 2) → 1.0 |
Math.toRadians(g) | Graus para radianos | Math.toRadians(180) → π |
Math.addExact(a, b) | Soma que avisa se estourar o int | veja 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 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étodo | Devolve | Exemplo → resultado |
|---|---|---|
Math.max(a, b) | tipo dos argumentos | Math.max(3, 7) → 7 |
Math.min(a, b) | tipo dos argumentos | Math.min(3, 7) → 3 |
Math.abs(x) | tipo do argumento | Math.abs(-10) → 10 |
Math.sqrt(x) | double | Math.sqrt(64) → 8.0 |
Math.pow(b, e) | double | Math.pow(2, 10) → 1024.0 |
Math.round(x) | long | Math.round(-2.5) → -2 |
Math.floor(x) | double | Math.floor(-2.5) → -3.0 |
Math.ceil(x) | double | Math.ceil(2.1) → 3.0 |
Math.random() | double em [0, 1) | 0.5897360548361562 |
Math.floorDiv(a, b) | int/long | Math.floorDiv(-7, 2) → -4 |
Math.floorMod(a, b) | int/long | Math.floorMod(-7, 2) → 1 |
Math.PI, Math.E | double | 3.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:
2. Sempre para cima
Uma van leva 8 pessoas. Para levar 30 pessoas, quantas vans? Complete com o método que arredonda para cima:
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 deimport.max,min,absmantêm o tipo;sqrt,pow,floor,ceildevolvemdouble;rounddevolvelong.roundvai para o mais próximo e, no empate, "para cima" (para o maior): 2.5 → 3, -2.5 → -2.floordesce,ceilsobe.- Duas casas:
Math.round(x * 100) / 100.0(com.0!). Para mostrar,String.format("%.2f", x); para dinheiro,BigDecimal. floorModdá um resto positivo: use em contas que "dão a volta" com negativos.Math.PIeMath.Esão constantes;Math.random()sorteia em [0, 1).