Javascript представляет в Number
качестве двойной точности 64-разрядных чисел с плавающей .
Math.floor
работает с этим в виду.
Битовые операции работают в 32 - битном подписал целые числа. 32-разрядные целые числа со знаком используют первый бит в качестве отрицательного значения, а остальные 31 бит - это число. Из-за этого допустимые минимальные и максимальные 32-разрядные числа со знаком составляют -2 147 483 648 и 2147483647 (0x7FFFFFFFF) соответственно.
Поэтому, когда вы делаете | 0
, вы, по сути, делаете это & 0xFFFFFFFF
. Это означает, что любое число, представленное как 0x80000000 (2147483648) или выше, будет возвращено как отрицательное число.
Например:
// Safe
(2147483647.5918 & 0xFFFFFFFF) === 2147483647
(2147483647 & 0xFFFFFFFF) === 2147483647
(200.59082098 & 0xFFFFFFFF) === 200
(0X7FFFFFFF & 0xFFFFFFFF) === 0X7FFFFFFF
// Unsafe
(2147483648 & 0xFFFFFFFF) === -2147483648
(-2147483649 & 0xFFFFFFFF) === 2147483647
(0x80000000 & 0xFFFFFFFF) === -2147483648
(3000000000.5 & 0xFFFFFFFF) === -1294967296
Также. Побитовые операции не "пол". Они усекаются , что равносильно тому , чтобы сказать, они круглые ближе всего к 0
. После того, как вы идете вокруг отрицательных чисел Math.floor
раундов вниз в то время как побитовое начинают округлять вверх .
Как я уже говорил, Math.floor
безопаснее, потому что он работает с 64-битными числами с плавающей запятой. Побитовый - быстрее , да, но ограничен 32-битной областью со знаком.
Подвести итоги:
- Побитовая работает так же, если вы работаете с
0 to 2147483647
.
- Поразрядно 1 номер, если вы работаете с
-2147483647 to 0
.
- Побитовое полностью отличается для чисел меньше
-2147483648
и больше, чем 2147483647
.
Если вы действительно хотите настроить производительность и использовать оба:
function floor(n) {
if (n >= 0 && n < 0x80000000) {
return n & 0xFFFFFFFF;
}
if (n > -0x80000000 && n < 0) {
return (n - 1) & 0xFFFFFFFF;
}
return Math.floor(n);
}
Просто добавить Math.trunc
работает как побитовые операции. Так что вы можете сделать это:
function trunc(n) {
if (n > -0x80000000 && n < 0x80000000) {
return n & 0xFFFFFFFF;
}
return Math.trunc(n);
}