Число.sign () в javascript
интересно, есть ли нетривиальные способы найти знак числа ( функция signum)?
Может быть короче / быстрее / более элегантные решения, чем очевидный
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
короткая выдержка
использовать это, и вы будете в безопасности и быстро
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
результаты
на данный момент у нас есть следующие решения:
1. очевидное и быстро
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. модификация от kbec - один тип броска меньше, более производительный, короче [быстрый]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
внимание:sign("0") -> 1
2. элегантный, короткий, не так быстро [медленный]
function sign(x) { return x && x / Math.abs(x); }
внимание:sign(+-Infinity) -> NaN
,sign("0") -> NaN
по состоянию на Infinity
является юридическим номером в JS это решение не кажется совершенно верно.
3. искусство... но очень медленно [медленный]
function sign(x) { return (x > 0) - (x < 0); }
4. С помощью bit-shift
быстро, но!--12-->
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Type-safe [megafast]
! похоже, что браузеры (особенно V8 chrome) делают некоторые волшебные оптимизации, и это решение оказывается намного больше performant чем другие, даже чем (1.1) несмотря на то, что он содержит 2 дополнительные операции и логически никогда не может быть быстрее.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
инструменты
улучшению приветствуются!
[Offtopic] принятый ответ
Андрей Таранцов- + 100 за искусство, но грустно это примерно в 5 раз медленнее, чем очевидный подход
Фредерик Хамиди-как-то самый популярный ответ (на время написания), и это здорово, но это определенно не так, как все должно быть сделано, имхо. Также он неправильно обрабатывает бесконечные числа, которые также являются числами, вы знаете.
kbec-это улучшение очевидного решения. Не то чтобы революционно, но все вместе я считаю этот подход лучшим. Голос для него :)
14 ответов:
деление числа на его абсолютное значение также дает его знак. Использование логического и оператора короткого замыкания позволяет нам использовать специальный случай
0
поэтому мы не делим на него:var sign = number && number / Math.abs(number);
функция, которую вы ищете, называется signum, и лучший способ реализовать это:
function sgn(x) { return (x > 0) - (x < 0); }
не должно ли это поддерживать подписанные нули JavaScript (ECMAScript)? Кажется, это работает при возврате x, а не 0 в функции "megafast":
function sign(x) { return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN; }
это делает его совместимым с проектом математика ECMAScript.знак (MDN):
возвращает знак x, указывающий, является ли x положительным, отрицательным или нулевым.
- если x-NaN, то результат-NaN.
- если x равно -0, то результат это -0.
- если x равно +0, то результат равен +0.
- если x отрицательно и не -0, то результат равен -1.
- если x положительно, а не +0, то результат равен +1.
для людей, которым интересно, что происходит с последними браузерами, в версии ES6 есть родной математика.знак метод. Вы можете проверить поддержка.
в основном он возвращает
-1
,1
,0
илиNaN
Math.sign(3); // 1 Math.sign(-3); // -1 Math.sign('-3'); // -1 Math.sign(0); // 0 Math.sign(-0); // -0 Math.sign(NaN); // NaN Math.sign('foo'); // NaN Math.sign(); // NaN
var sign = number >> 31 | -number >>> 31;
сверхбыстрый, если вам не нужна бесконечность и вы знаете, что число является целым числом, найденным в OpenJDK-7 source:
java.lang.Integer.signum()
думаю, что это просто для удовольствия:
function sgn(x){ return 2*(x>0)-1; }
0 и NaN вернет -1
отлично работает на + / - бесконечность
решение, которое работает на всех числах, а также
0
и-0
, а такжеInfinity
и-Infinity
, является:function sign( number ) { return 1 / number > 0 ? 1 : -1; }
на вопрос "а +0 и -0 то же самое?" для получения дополнительной информации.
предупреждение: ни один из этих ответов, включая теперь стандартный
Math.sign
будет работать над делом0
vs-0
. Это может быть не проблема для вас, но в некоторых реализациях физики это может быть вопрос.
вы можете немного сдвинуть число и проверить самый значительный бит (MSB). Если MSB-это 1, то число отрицательное. Если это 0, то число положительное (или 0).
Я просто собирался задать тот же вопрос, но пришел к решению, прежде чем я закончил писать, увидел, что этот вопрос уже существует, но не видел этого решения.
(n >> 31) + (n > 0)
кажется, это быстрее, добавив троичный, хотя
(n >> 31) + (n>0?1:0)
очень похож на ответ Мартейн составляет
function sgn(x) { isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1)); }
Я нахожу его более читабельным. Кроме того (или, в зависимости от вашей точки зрения, однако), он также groks вещи, которые могут быть интерпретированы как число; например, он возвращает
-1
С'-5'
.
Я не вижу никакого практического смысла возвращения -0 и 0 от
Math.sign
Итак, моя версия:function sign(x) { x = Number(x); if (isNaN(x)) { return NaN; } if (x === -Infinity || 1 / x < 0) { return -1; } return 1; }; sign(100); // 1 sign(-100); // -1 sign(0); // 1 sign(-0); // -1
методы, которые я знаю, следующие:
математика.знак(Н)
var s = Math.sign(n)
это собственная функция, но медленнее всего из-за накладных расходов вызова функции. Однако он обрабатывает "NaN", где другие ниже могут просто предполагать 0 (т. е. математика.знак ('abc') - NaN).
((n>0) - (n
var s = ((n>0) - (n<0));
в этом случае только левая или правая сторона может быть 1 на основе знак. Это приводит к либо
1-0
(1),0-1
(-1), или0-0
(0).скорость этого кажется шея и шея со следующим ниже в Хроме.
(n>>31)|(!!n)
var s = (n>>31)|(!!n);
использует "арифметический сдвиг вправо". В основном сдвиг на 31 отбрасывает все биты, кроме знака. Если знак был установлен, это приводит к -1, в противном случае он равен 0. Право
|
он проверяет на положительный результат путем преобразования значения в boolean (0 или 1 [Кстати: нечисловые строки, например!!'abc'
, в этом случае становится 0, а не NaN]) затем использует побитовую операцию OR для объединения битов.это, кажется, лучший в среднем производительность во всех браузерах (лучше всего в Chrome и Firefox, по крайней мере), но не самый быстрый во всех из них. По какой-то причине тернарный оператор быстрее в IE.
n?n
var s = n?n<0?-1:1:0;
самый быстрый в IE для некоторых причина.
см. Этот тест jsperf
проведенные тесты:https://jsperf.com/get-sign-from-value
мои два цента, с функцией, которая возвращает те же результаты, что и математика.знак будет делать, т. е. знак(-0) --> -0, знак(-бесконечность) --> -бесконечности, знак(нуль) --> 0, знак(не определено) --> НАН и т. д.
function sign(x) { return +(x > -x) || (x && -1) || +x; }
Jsperf не позволит мне создать тест или ревизию, извините, что не могу предоставить вам тесты (я дал jsbench.github.io попробуйте, но результаты кажутся гораздо ближе друг к другу, чем с Jsperf...)
если кто-то может добавить его в редакцию Jsperf, я бы любопытно посмотреть, как это соотносится со всеми ранее приведенными решениями...
спасибо!
Джим.
EDIT:
Я должен был написать:
function sign(x) { return +(x > -x) || (+x && -1) || +x; }
(
(+x && -1)
вместо(x && -1)
) для того чтобы обрабатыватьsign('abc')
правильно (-->NaN)