Como Lua lida com números inteiros e números flutuantes?

11

Tanto quanto me lembro de programar, fui ensinado a não comparar números de ponto flutuante para igualdade. Agora, ao ler Programação em Lua sobre o numbertipo Lua , encontrei o seguinte:

O tipo de número representa números reais (ponto flutuante de precisão dupla). Lua não tem tipo inteiro, pois não precisa dele. Há um equívoco generalizado sobre erros aritméticos de ponto flutuante e algumas pessoas temem que mesmo um simples incremento possa ficar estranho com números de ponto flutuante. O fato é que, quando você usa um duplo para representar um número inteiro, não há nenhum erro de arredondamento (a menos que o número seja maior que 100.000.000.000.000). Especificamente, um número Lua pode representar qualquer número inteiro longo sem problemas de arredondamento. Além disso, a maioria das CPUs modernas faz aritmética de ponto flutuante tão rápido quanto (ou até mais rápido que) a aritmética inteira.

Isso é verdade para todos os idiomas? Basicamente, se não formos além do ponto flutuante em duplas, estaremos seguros na aritmética inteira? Ou, para estar mais de acordo com o título da pergunta, há algo especial que Lua faz com seu numbertipo, para que funcione bem como tipo inteiro e ponto flutuante?

Petr Abdulin
fonte
Veja também stackoverflow.com/questions/1848700/…
Joonas Pulakka
@JoonasPulakka obrigado, isso é uma adição bastante valiosa.
22413 Petr Petrulin

Respostas:

10

Lua afirma que os números de ponto flutuante podem representar números inteiros exatamente como os tipos inteiros, e estou inclinado a concordar. Não há representação imprecisa de uma parte numérica fracionária para lidar. Se você armazena um número inteiro em um tipo inteiro ou na mantissa de um número de ponto flutuante, o resultado é o mesmo: esse número inteiro pode ser representado exatamente, desde que você não exceda o número de bits na mantissa , + 1 bit no expoente.

Obviamente, se você tentar armazenar um número de ponto flutuante real (por exemplo, 12.345) em uma representação de ponto flutuante, todas as apostas serão desativadas; portanto, seu programa deve ficar claro que o número é realmente um número inteiro genuíno que não excede o mantissa, a fim de tratá-lo como um número inteiro real (isto é, com relação à comparação da igualdade).

Se você precisar de mais precisão inteira do que isso, sempre poderá empregar uma biblioteca de precisão arbitrária .

Leitura adicional
Qual é o valor máximo de um número em Lua?

Robert Harvey
fonte
E o segundo argumento, ou seja, que o ponto flutuante é tão rápido ou mais rápido que a aritmética inteira nas CPUs modernas? Parece-me duvidoso, mesmo ao usar números de ponto flutuante para executar aritmética inteira.
Andres F.
2
@AndresF. Não vejo como é mais rápido, a menos que você elimine um elenco usando um único tipo numérico em vez de dois.
Robert Harvey
Acordado. Não faz nenhum sentido para mim. Gostaria de saber se é retirado de contexto ...
Andres F.
1
Inteiros suficientemente grandes não podem ser armazenados exatamente em um objeto de ponto flutuante. Um de 64 bits doublepossui cerca de 51 ou mais bits de mantissa; números inteiros ímpares maiores que 2 ** 51 terão erros de arredondamento. Um número inteiro de 64 bits pode armazenar valores inteiros maiores exatamente, pois não dedica nenhum bit a um expoente.
21413 Keith Thompson
@ KeithThompson: Eu pensei que isso estava implícito na minha resposta quando eu disse "armazenado na mantissa". No entanto, editarei a resposta para esclarecer.
Robert Harvey
5

Os duplos são armazenados como uma mantissa e um expoente. Veja o formato para mais informações. Basicamente, todos os números têm a forma: mantissa * 2 expoente . Para qualquer número inteiro menor que 2 52 , o expoente será zero, tornando a mantissa bit a bit equivalente a um número inteiro não assinado de 52 bits. Um bit de sinal separado é usado para indicar números negativos.

Na verdade, até mesmo alguns números inteiros maiores que 2 52 pode ser representado exatamente, desde que todos os dígitos após os 52 nd são zeros. Além disso, algumas frações, como 0,5, podem ser representadas exatamente. É somente quando a fração está repetindo continuamente (como 1/3) na base 2, ou requer muitos bits além do ponto de raiz que você perde a precisão.

Karl Bielefeldt
fonte
Não é por causa da repetição contínua de decimais. Isso ocorre porque muitos números decimais (base dez) não podem ser representados exatamente como uma potência de dois.
Robert Harvey
2
Na base 2, os números que não podem ser representados exatamente seriam repetidos continuamente. Por exemplo, 0,1 decimal se torna 0,0 (0011) em binário, com o 0011 repetindo continuamente.
Karl Bielefeldt
2
Sim, exatamente. Mas não repetindo na base 10. Repetindo na base 2.
Robert Harvey