Мой коллега наткнулся на метод для получения чисел с плавающей запятой с использованием побитового или:
var a = 13.6 | 0; //a == 13
Мы говорили об этом и задавались вопросом несколько вещей.
- Как это работает? Наша теория заключалась в том, что использование такого оператора приводит число к целому числу, удаляя дробную часть
- Есть ли у него какие-либо преимущества по сравнению с этим
Math.floor
? Может быть, это немного быстрее? (каламбур не предназначен) - Есть ли у него недостатки? Может быть, это не работает в некоторых случаях? Ясность очевидна, так как мы должны были это выяснить, и я пишу этот вопрос.
Спасибо.
javascript
floating-point
bit-manipulation
Алекс Турпин
источник
источник
3000000000.1 | 0
оценивается в -1294967296. Таким образом, этот метод не может быть применен для расчета денег (особенно в случаях, когда вы умножаете на 100, чтобы избежать десятичных чисел).0.1 + 0.2 == 0.3
в консоли JavaScript. Если ваш язык поддерживает это, вы должны использовать десятичный тип. Если нет, храните центы вместо этого.Ответы:
Все побитовые операции, кроме беззнакового сдвига вправо
>>>
, работают с 32-разрядными целыми числами со знаком. Таким образом, использование побитовых операций преобразует число с плавающей точкой в целое число.http://jsperf.com/or-vs-floor/2 кажется немного быстрее
Math.floor(NaN) === NaN
пока(NaN | 0) === 0
источник
Math.floor(NaN) === NaN
, что пока(NaN | 0) === 0
. Эта разница может быть важной в некоторых приложениях.asm.js
(где я впервые узнал об этом). Это быстрее, если ни по какой другой причине, потому что это не вызывает функцию наMath
объекте, функцию, которая могла бы быть в любое время заменена как вMath.floor = function(...)
.(value | 0) === value
может использоваться для проверки того, что значение на самом деле является целым числом и только целым числом (как в исходном коде Elm @ dwayne-crooks связанный). Иfoo = foo | 0
может использоваться для приведения любого значения к целому числу (где 32-битные числа усекаются и все не числа становятся 0).Это усечение в отличие от настила. Ответ Ховарда вроде правильный; Но я бы добавил, что
Math.floor
делает именно то, что положено в отношении отрицательных чисел. Математически это и есть пол.В случае, который вы описали выше, программист больше интересовался усечением или отключением десятичной дроби. Хотя синтаксис, который они использовали, скрывает тот факт, что они конвертируют float в int.
источник
Math.floor(8589934591.1)
дает ожидаемый результат, не8589934591.1 | 0
делает .В ECMAScript 6 эквивалентом
|0
является Math.trunc , вроде бы я должен сказать:источник
Math.trunc()
работают с числом выше или равным 2 ^ 31 и| 0
нетВаш первый пункт верен. Число приводится к целому числу, и поэтому любые десятичные цифры удаляются. Обратите внимание, что
Math.floor
округляется до следующего целого числа в сторону минус бесконечность и, таким образом, дает другой результат применительно к отрицательным числам.источник
Javascript представляет в
Number
качестве двойной точности 64-разрядных чисел с плавающей .Math.floor
работает с этим в виду.Битовые операции работают в 32 - битном подписал целые числа. 32-разрядные целые числа со знаком используют первый бит в качестве отрицательного значения, а остальные 31 бит - это число. Из-за этого допустимые минимальные и максимальные 32-разрядные числа со знаком составляют -2 147 483 648 и 2147483647 (0x7FFFFFFFF) соответственно.
Поэтому, когда вы делаете
| 0
, вы, по сути, делаете это& 0xFFFFFFFF
. Это означает, что любое число, представленное как 0x80000000 (2147483648) или выше, будет возвращено как отрицательное число.Например:
Также. Побитовые операции не "пол". Они усекаются , что равносильно тому , чтобы сказать, они круглые ближе всего к
0
. После того, как вы идете вокруг отрицательных чиселMath.floor
раундов вниз в то время как побитовое начинают округлять вверх .Как я уже говорил,
Math.floor
безопаснее, потому что он работает с 64-битными числами с плавающей запятой. Побитовый - быстрее , да, но ограничен 32-битной областью со знаком.Подвести итоги:
0 to 2147483647
.-2147483647 to 0
.-2147483648
и больше, чем2147483647
.Если вы действительно хотите настроить производительность и использовать оба:
Просто добавить
Math.trunc
работает как побитовые операции. Так что вы можете сделать это:источник
В спецификациях говорится, что оно конвертируется в целое число:
Производительность: это было проверено на jsperf раньше.
примечание: мертвая ссылка на спецификацию удалена
источник