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);
}