Целочисленное деление Javascript, или Math.floor (x) эквивалентно x | 0 для х> = 0? - PullRequest
1 голос
/ 22 февраля 2012

Глядя на следующие примеры, похоже, что Math.floor(x) эквивалентно x | 0 для x >= 0. Это действительно так? Если да, то почему? (или как рассчитывается x | 0?)

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

Это может быть полезно для целочисленного деления в Javascript: (5 / 3) | 0 вместо Math.floor(5 / 3).

Ответы [ 5 ]

4 голосов
/ 22 февраля 2012

Битовые операторы преобразуют числа в 32-битную последовательность. Таким образом, предлагаемые вами альтернативы будут работать только с 32-разрядными числами с положительными знаками, то есть числами от 0 до +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

Другое отличие: если x не является числом, результат x | 0 может отличаться от результата Math.floor(x).

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

Кроме этого, результат должен быть аналогичен результату Math.floor(), если используется положительное число.

Вот еще несколько примеров + тесты производительности: http://jsperf.com/rounding-numbers-down

3 голосов
/ 22 февраля 2012

Согласно Спецификация ECMAScript , §11.10 Бинарные побитовые операторы:

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.

Вот как рассчитывается x | y: x и y анализируются до Int32, а затем к ним применяется оператор |.

2 голосов
/ 22 февраля 2012

Вертикальная черта - это побитовый оператор.Поскольку все биты 0 равны нулю, x|0 в теории не работает.Но чтобы оценить его, операнды должны быть целыми числами, поэтому x необходимо сначала преобразовать из числа с плавающей запятой в целое число.Преобразование выполняется путем исключения дробной части, поэтому да, для некоторого x> = 0 мы имеем x|0 == Math.floor(x).

Обратите внимание, что результат зависит от размера и знака внутреннего целого числатип.Например, вы получаете:

2147483648|0     == -2147483648     // 0x80000000
Math.pow(2,32)|0 == 0               // the lowest 32 bits are all 0
2 голосов
/ 22 февраля 2012

Битовые операции в JS являются 32-битными, то есть число с плавающей запятой сначала «приводится» в «int».

"2.6" | 0 = 2 предполагает, что parseInt вызывается.

1 голос
/ 22 февраля 2012

(x | 0) удаляет биты после «.», Поэтому мы можем получить следующее истинное отношение:

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

x >> 0 имеет тот же эффект, что и x |0, так:

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