Índice:
Vídeo: 10.6: Pixel Neighbors - Processing Tutorial 2024
Acredite ou não, os computadores - mesmo os mais poderosos - têm certas limitações quando se trata de realizar cálculos matemáticos. Essas limitações são geralmente insignificantes, mas às vezes elas se aproximam e mordem você. Aqui estão as coisas que você precisa prestar atenção ao fazer matemática em Java.
Sobrecarga inteira
O problema básico com os tipos inteiros é que eles têm um tamanho fixo. Como resultado, existe um limite para o tamanho dos números que podem ser armazenados em variáveis do tipo
curto
,
int
ou
long
. Embora
long
variáveis podem conter números que são enormes, mais cedo ou mais tarde, você se deparar com um número que é muito grande para se ajustar a uma variável
longa
.
Certo, considere este (possivelmente inventado) exemplo:
int a = 1000000000;
Sistema. Fora. println (a);
a + = 1000000000;
Sistema. Fora. println (a);
a + = 1000000000;
Sistema. Fora. println (a);
a + = 1000000000;
Sistema. Fora. println (a);
Aqui você espera que o valor de
a
seja maior após cada adição. Mas aqui está a saída exibida:
1000000000
2000000000
-1294967296
-294967296
A primeira adição parece funcionar, mas depois disso, o número se torna negativo! Isso ocorre porque o valor atingiu o limite de tamanho do tipo de dados
int
. Infelizmente, o Java não diz que esse erro aconteceu. Ele simplesmente crams a variável
int
como cheia de bits, pode descartar os bits que não se encaixam e espera que você não perceba. Devido ao modo
int
armazena valores negativos, os grandes valores positivos de repente tornam-se grandes valores negativos.
A moral da história é que, se você estiver trabalhando com números inteiros grandes, você deve usar
long
em vez de
int
, porque
longo
pode armazenar números muito maiores do que
int
. Se seus programas lidam com números grandes o suficiente para ser um problema para
long
, considere usar tipos de ponto flutuante em vez disso. Os tipos de ponto flutuante podem lidar com valores ainda maiores do que
long
, e eles permitem que você saiba quando você excede sua capacidade.
Risco de ponto flutuante
Os números de ponto flutuante têm problemas próprios. Para iniciantes, os números de ponto flutuante são armazenados usando o sistema de números binários (base 2), mas os seres humanos trabalham com números no sistema de números decimais (base 10). Infelizmente, as conversões com precisão desses dois sistemas às vezes são impossíveis. Isso ocorre porque em qualquer base de números, certas frações não podem ser representadas exatamente.
Um exemplo: Base 10 não tem como representar exatamente a fração 1/3. Você pode aproximá-lo como 0. 3333333, mas eventualmente você atinge o limite de quantos dígitos você pode armazenar, então você tem que parar. Na base 2, acontece que uma das frações que você não pode representar com precisão é o valor decimal 1/10. Em outras palavras, uma
float
ou
dupla
variável não pode representar com precisão
0. 1
.
Tente executar este código:
float x = 0. 1f;
NumberFormat nf = NumberFormat. getNumberInstance ();
nf. setMinimumFractionDigits (10);
Sistema. Fora. println (nf. format (x));
A saída resultante é esta:
0. 1000000015
Embora
0. 1000000015
é fechar a
0. 1
, não é exato.
Na maioria dos casos, as matemáticas de ponto flutuante de Java estão próximas o suficiente para não importar. A margem de erro é extremamente pequena. Se você estiver usando o Java para medir o tamanho da sua casa, você precisaria de um microscópio eletrônico para notar o erro. Se você estiver escrevendo aplicativos que lidam com transações financeiras, no entanto, o arredondamento normal às vezes pode ampliar os erros para torná-los significativos. Você pode cobrar um centavo demais ou muito pouco imposto sobre vendas. E em casos extremos, suas faturas podem realmente ter erros óbvios de adição.
Os tipos inteiros são armazenados em binário também, é claro. Mas os números inteiros não estão sujeitos aos mesmos erros que os tipos de ponto flutuante são - porque os números inteiros não representam frações de forma alguma - para que você não precise se preocupar com esse tipo de erro para os tipos
inteiros
.
Divisão por zero
De acordo com as regras básicas da matemática, você não pode dividir um número por zero. A razão é simples: a divisão é o inverso da multiplicação - o que significa que se
a * b = c
, também é verdade que
a = c / b
. Se você fosse permitir que
b
fosse zero, a divisão não teria sentido, porque qualquer número vezes zero é zero. Portanto, ambos
a
e
c
também devem ser zero. Em suma, os matemáticos resolveram esse dilema há séculos dizendo que a divisão por zero simplesmente não é permitida.
Então, o que acontece se fazer tentar dividir um número por zero em um programa Java? A resposta depende se você está dividindo números inteiros ou números de ponto flutuante. Se você estiver dividindo inteiros, a declaração que tenta a divisão por zero bloqueia o que é chamado de uma exceção,, que é uma maneira impulso de falhar o programa.
Existe uma maneira de interceptar esta exceção para permitir que seu programa continue, o que você não encontra aqui. Enquanto isso, qualquer programa que você escreve que tente uma divisão inteira por zero acidentes.
Se você tentar dividir um tipo de ponto flutuante por zero, os resultados não são tão abruptos. Em vez disso, o Java atribui ao resultado de ponto flutuante um dos valores especiais listados na tabela abaixo. Os parágrafos a seguir explicam como esses valores especiais são determinados:
- Se você dividir um número por zero e o sinal de ambos os números é o mesmo, o resultado é infinito positivo.
0. 0
dividido por0. 0
é infinito positivo, como é-34. 0
dividido por-0. 0
. - Se você dividir um número por zero, e os sinais dos números são diferentes, o resultado é o infinito negativo.
-40. 0
dividido por0. 0
é infinito negativo, como é34. 0
dividido por0. 0
. - Se você dividir zero por zero, o resultado não é um número (NaN), independentemente dos sinais.
Constante | Significado |
POSITIVE_INFINITY
|
Infinito positivo |
NEGATIVO_INFINIDADE
|
Infinito negativo |
NaN
|
Não é um número |
Os zeros de ponto flutuante podem ser positivos ou negativos. Java considera que os zeros positivos e negativos são iguais numericamente.
Se você tentar imprimir um valor de ponto flutuante que tenha um desses valores especiais, Java converte o valor em uma seqüência apropriada. Suponha que você execute as seguintes instruções:
duplo x = Matemática. sqrt (-50); // Não é um número
duplo y = x;
se (x == y)
Sistema. Fora. println ("x é igual a y");
A saída resultante da consola é
Infinity
Se
i
foram
-50. 0
, o console exibiria
-Infinidade
, e se
i
fossem zero, o console exibiria
NaN
.
Os parágrafos seguintes descrevem alguns bits finais de estranheza:
-
NaN
não é igual a si mesmo, o que pode ter algumas conseqüências estranhas. Por exemplo:
duplo x = Matemática. sqrt (-50); // Não é um número
duplo y = x;
se (x == y)
Sistema. Fora. println ("x é igual a y");
Basta supor, por razões de argumento, que a instrução
se
verifica se a variável
x
é igual à variável
y
. Como este teste segue imediatamente uma declaração de atribuição que atribui o valor de
x
a
y
, você pode assumir com segurança que
x
é igual a
y
, certo?
Errado. Como
x
é
NaN
,
y
também é
NaN
.
NaN
nunca é considerado igual a qualquer outro valor, incluindo outro
NaN
. Assim, a comparação na indicação
se
falhar.
- Outra consequência estranha: você não pode assumir que um número menos ele próprio é sempre zero. Considere esta afirmação:
double z = x - x; // não necessariamente zero
Essa afirmação não deve ser definida
z
para zero? Não se
x
for
NaN
. Nesse caso, nem um número menos nenhum número ainda não é um número.
- Mais uma estranheza: qualquer operação matemática que envolve resultados infinitos em qualquer outro infinito ou
NaN
. Infinity + 5, por exemplo, ainda é igual ao infinito, então a chamada de Buzz Lightyear "Para infinito e além! "Simplesmente não vai acontecer. Mas o infinito menos o infinito dá-lhe …NaN
.