Pergunta

Observando os exemplos a seguir, parece que Math.floor(x) é equivalente a x | 0, para x >= 0.Isso é verdade?Se sim, por quê?(ou como o x | 0 é calculado?)

x = -2.9; console.log(Math.floor(x) + ", " + (x | 0));   // -3, -2
x = -2.3; console.log(Math.floor(x) + ", " + (x | 0));   // -3, -2
x = -2;   console.log(Math.floor(x) + ", " + (x | 0));   // -2, -2
x = -0.5; console.log(Math.floor(x) + ", " + (x | 0));   // -1, 0
x = 0;    console.log(Math.floor(x) + ", " + (x | 0));   //  0, 0
x = 0.5;  console.log(Math.floor(x) + ", " + (x | 0));   //  0, 0
x = 2;    console.log(Math.floor(x) + ", " + (x | 0));   //  2, 2
x = 2.3;  console.log(Math.floor(x) + ", " + (x | 0));   //  2, 2
x = 2.9;  console.log(Math.floor(x) + ", " + (x | 0));   //  2, 2
x = 3.1;  console.log(Math.floor(x) + ", " + (x | 0));   //  3, 3

Isso pode ser útil para realizar a divisão de inteiros em Javascript: (5 / 3) | 0 em vez de Math.floor(5 / 3).

Foi útil?

Solução

Os operadores bit a bit convertem números em uma sequência de 32 bits.Portanto, as alternativas que você está sugerindo só funcionarão com flutuadores de 32 bits com sinal positivo, ou seja, números de 0 a +2,147,483,647 (2^31-1).

Math.floor(2147483646.4); // 2147483647
2147483646.4 | 0; // 2147483647
// but…
Math.floor(2147483648.4); // 2147483648
2147483648.4 | 0; // -2147483648

Outra diferença: se x não for um número, o resultado de x | 0 pode ser diferente do Math.floor(x).

Math.floor(NaN); // NaN
NaN | 0; // 0

Fora isso, o resultado deve ser semelhante ao de Math.floor(), desde que um número positivo seja usado.

Aqui estão mais alguns exemplos + testes de desempenho: http://jsperf.com/rounding-numbers-down

Outras dicas

De acordo com especificação ECMAScript , §11.10 Operadores binários bit a bit:

Semantics
The production A : A @ B, where @ is one of the bitwise operators in the productions 
above, is evaluated as follows:
1. Let lref be the result of evaluating A.
2. Let lval be GetValue(lref).
3. Let rref be the result of evaluating B.
4. Let rval be GetValue(rref).
5. Let lnum be ToInt32(lval).
6. Let rnum be ToInt32(rval).
7. Return the result of applying the bitwise operator @ to lnum and rnum. The result 
   is a signed 32 bit integer.

É assim que o x | y é calculado: x e y são analisados em Int32 e, em seguida, aplicam-se o operador | a eles.

As operações bit a bit em JS são de 32 bits, ou seja, o float é primeiro "convertido" em um "int".

"2.6" | 0 = 2 sugere que parseInt está sendo chamado.

A barra vertical é o operador bit a bit ou.Como os bits de 0 são todos zero, x|0 é, em teoria, um ambiente autônomo.Mas, para avaliá-lo, os operandos devem ser inteiros, então x deve ser convertido de ponto flutuante em um inteiro primeiro.A conversão é feita eliminando a parte fracionária, então sim, para algum x>= 0 temos x|0== Math.floor(x).

Observe que o resultado depende do tamanho e do sinal do tipo inteiro interno.Por exemplo, você obtém:

2147483648|0     == -2147483648     // 0x80000000
Math.pow(2,32)|0 == 0               // the lowest 32 bits are all 0

(x | 0) remove os bits após ".", para que possamos obter a próxima relação verdadeira:

x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;

x >> 0 tem o mesmo efeito que x |0, então:

x >> 0 = x | 0 = (x < 0 ? -1 : 1) * Math.floor(Math.abs(x)) ;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top