Um colega meu encontrou um método para calcular números flutuantes usando um bit a bit ou:
var a = 13.6 | 0; //a == 13
Estávamos conversando sobre isso e imaginando algumas coisas.
- Como funciona? Nossa teoria era que o uso de um operador desse tipo lança o número para um número inteiro, removendo a parte fracionária
- Tem alguma vantagem sobre fazer
Math.floor
? Talvez seja um pouco mais rápido? (trocadilho não pretendido) - Tem alguma desvantagem? Talvez não funcione em alguns casos? A clareza é óbvia, já que tínhamos que descobrir, e bem, estou escrevendo essa pergunta.
Obrigado.
javascript
floating-point
bit-manipulation
Alex Turpin
fonte
fonte
3000000000.1 | 0
avalia para -1294967296. Portanto, esse método não pode ser aplicado para cálculos de dinheiro (especialmente nos casos em que você multiplica por 100 para evitar números decimais).0.1 + 0.2 == 0.3
em um console JavaScript. Se o seu idioma suportar, você deve usar um tipo decimal. Caso contrário, armazene centavos.Respostas:
Todas as operações bit a bit, exceto shift direito não assinado
>>>
, funcionam em números inteiros de 32 bits assinados. Portanto, o uso de operações bit a bit converterá um float em um número inteiro.http://jsperf.com/or-vs-floor/2 parece um pouco mais rápido
Math.floor(NaN) === NaN
enquanto(NaN | 0) === 0
fonte
Math.floor(NaN) === NaN
, enquanto(NaN | 0) === 0
. Essa diferença pode ser importante em alguns aplicativos.asm.js
(onde eu aprendi sobre isso). É mais rápido, se não por outro motivo, porque não está chamando uma função noMath
objeto, uma função que pode ser substituída a qualquer momento como emMath.floor = function(...)
.(value | 0) === value
pode ser usado para verificar se um valor é de fato um número inteiro e apenas um número inteiro (como no código-fonte Elm @ dwayne-crooks linked). Efoo = foo | 0
pode ser usado para coagir qualquer valor a um número inteiro (onde números de 32 bits são truncados e todos os não números se tornam 0).Isso é truncamento em oposição ao revestimento. A resposta de Howard é meio correta; Mas eu acrescentaria que
Math.floor
faz exatamente o que é suposto com relação a números negativos. Matematicamente, é isso que é um piso.No caso descrito acima, o programador estava mais interessado em truncar ou cortar o decimal completamente. Embora a sintaxe que eles usaram oculte o fato de que eles estão convertendo o float em um int.
fonte
Math.floor(8589934591.1)
produz o resultado esperado,8589934591.1 | 0
NÃO .No ECMAScript 6, o equivalente a
|0
é Math.trunc , devo dizer:fonte
Math.trunc()
do trabalho com o número maior ou igual a 2 ^ 31 e| 0
nãoSeu primeiro ponto está correto. O número é convertido em um número inteiro e, portanto, qualquer dígito decimal é removido. Observe que isso
Math.floor
arredonda para o próximo número inteiro no sentido de menos infinito e, portanto, fornece um resultado diferente quando aplicado a números negativos.fonte
Javascript representa
Number
como números flutuantes de precisão dupla de 64 bits .Math.floor
trabalha com isso em mente.As operações bit a bit funcionam em números inteiros assinados de 32 bits . Inteiros com sinal de 32 bits usam o primeiro bit como significante negativo e os outros 31 bits são o número. Por esse motivo, os números mínimo e máximo permitidos para números assinados de 32 bits são -2.147.483.648 e 2147483647 (0x7FFFFFFFF), respectivamente.
Então, quando você está fazendo
| 0
, você está essencialmente fazendo é& 0xFFFFFFFF
. Isso significa que qualquer número representado como 0x80000000 (2147483648) ou superior retornará como um número negativo.Por exemplo:
Além disso. As operações bit a bit não "atendem". Eles truncam , o que é o mesmo que dizer, eles se aproximam mais
0
. Depois de ir ao redor para números negativos,Math.floor
rodadas para baixo , enquanto start bit a bit arredondamento para cima .Como eu disse antes,
Math.floor
é mais seguro porque opera com números flutuantes de 64 bits. Bitwise é mais rápido , sim, mas limitado ao escopo assinado de 32 bits.Para resumir:
0 to 2147483647
.-2147483647 to 0
.-2147483648
e maiores que2147483647
.Se você realmente deseja ajustar o desempenho e usar os dois:
Apenas para adicionar
Math.trunc
trabalhos como operações bit a bit. Então você pode fazer isso:fonte
As especificações dizem que é convertido em um número inteiro:
Desempenho: isso já foi testado no jsperf .
nota: link morto para especificação removida
fonte