Интересно, есть ли какие-нибудь нетривиальные способы найти знак числа ( сигнум-функция )?
Может быть короче / быстрее / элегантнее, чем очевидное
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Короткий ответ!
Используйте это, и вы будете в безопасности и быстро (источник: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Вы можете посмотреть на производительность и типа принуждающему сравнения скрипки
Прошло много времени. Дальнейшее происходит в основном по историческим причинам.
Полученные результаты
На данный момент у нас есть следующие решения:
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. Быстрое использование битового сдвига
, ноsign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Безопасный тип [мегабыстрый]
! Похоже, браузеры (особенно chrome v8) делают некоторые волшебные оптимизации, и это решение оказывается намного более производительным, чем другие, даже чем (1.1), несмотря на то, что оно содержит 2 дополнительные операции и, по логике, никогда не может быть быстрее.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
инструменты
Улучшения приветствуются!
[Offtopic] Ответ принят
Андрей Таранцов - +100 за искусство, но, к сожалению, это примерно в 5 раз медленнее очевидного подхода.
Фредерик Хамиди - ответ, получивший наибольшее количество голосов (на тот момент, когда я писал), и это вроде как круто, но это определенно не то, как надо делать, imho. Кроме того, он неправильно обрабатывает бесконечные числа, которые, как вы знаете, тоже являются числами.
kbec - это усовершенствование очевидного решения. Не то чтобы революционно, но в совокупности считаю такой подход лучшим. Проголосуйте за него :)
источник
0
Дело в том, что иногда это особый случайtest everything
версию, Safe откажется проверять специальные значения, так что это будет быстрее!only integers
Вместо этого попробуйте запустить тест. Кроме того, JSPerf просто выполняет свою работу, и это не значит, что это нравится. :)typeof x === "number"
магии производительности. Пожалуйста, сделайте больше запусков, особенно FF, Opera и IE, чтобы было понятно.Math.sign()
(0 === 0, не так быстро, как "Safe"), который появился в FF25 и скоро появится в Chrome.Ответы:
Более элегантный вариант быстрого решения:
источник
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
Деление числа на его абсолютное значение также дает его знак. Использование короткозамкнутого логического оператора AND позволяет нам использовать особый случай,
0
поэтому мы не в конечном итоге разделяем его:источник
var sign = number && number / Math.abs(number);
наnumber = 0
0
должно быть в специальном регистре. Ответ обновлен соответственно. Спасибо :)Функция, которую вы ищете, называется signum , и лучший способ ее реализовать:
источник
Должно ли это не поддерживать подписанные нули JavaScript (ECMAScript)? Кажется, это работает при возврате x, а не 0 в функции «мегабыстрая»:
Это делает его совместимым с черновиком ECMAScript Math.sign ( MDN ):
источник
Для людей, которым интересно, что происходит с последними версиями браузеров, в версии ES6 есть собственный метод Math.sign . Вы можете проверить поддержку здесь .
В основном он возвращается
-1
,1
,0
илиNaN
источник
Сверхбыстрый, если вам не нужна Infinity и вы знаете, что это целое число, найденное в источнике openjdk-7:
java.lang.Integer.signum()
источник
Я думал, что добавлю это просто для удовольствия:
0 и NaN вернет -1
отлично работает на +/- Infinity
источник
Решение, которое работает со всеми числами, а также с
0
и-0
, а также сInfinity
и-Infinity
:См. Вопрос « +0 и -0 - одно и то же? » Для получения дополнительной информации.
Внимание: Ни один из этих ответов, в том числе в настоящее время стандартного
Math.sign
будут работать по делу0
против-0
. Возможно, это не проблема для вас, но в некоторых реализациях физики это может иметь значение.источник
Вы можете сдвинуть число и проверить старший бит (MSB). Если MSB равен 1, то число отрицательное. Если 0, то число положительное (или 0).
источник
var sign = number < 0 : 1 : 0
n & 0x80000000
как битовую маску. Что касается преобразования в 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
и он сломался.ToInt32
. Если вы читаете там (раздел 9.5), есть модуль, который влияет на значение чисел, поскольку диапазон 32-битного целого числа меньше диапазона типа js Number. Так что это не сработает для этих значений или бесконечностей. Хотя мне все еще нравится ответ.Я как раз собирался задать тот же вопрос, но пришел к решению еще до того, как закончил писать, увидел, что этот вопрос уже существует, но не видел этого решения.
(n >> 31) + (n > 0)
кажется, что быстрее, если добавить троичный
(n >> 31) + (n>0?1:0)
источник
Очень похоже на ответ Мартейна:
Я считаю его более читаемым. Кроме того (или, однако, в зависимости от вашей точки зрения), он также глотает вещи, которые можно интерпретировать как числа; например, он возвращается
-1
при представлении'-5'
.источник
Я не вижу практического смысла возвращать -0 и 0,
Math.sign
поэтому моя версия:источник
Я знаю следующие методы:
Math.sign (сущ.)
var s = Math.sign(n)
Это собственная функция, но она работает медленнее всего из-за накладных расходов на вызов функции. Однако он обрабатывает «NaN», тогда как другие ниже могут просто принять 0 (т.е. Math.sign ('abc') равен NaN).
((п> 0) - (п <0))
var s = ((n>0) - (n<0));
В этом случае только левая или правая сторона может быть 1 в зависимости от знака. Результатом является либо
1-0
(1),0-1
(-1), либо0-0
(0).Скорость этого, похоже, шире, чем у следующего ниже в Chrome.
(п >> 31) | (!! п)
var s = (n>>31)|(!!n);
Использует «сдвиг вправо с распространением знака». Обычно сдвиг на 31 сбрасывает все биты, кроме знака. Если знак был установлен, это приводит к -1, в противном случае - 0. Справа от
|
него проверяется положительное значение путем преобразования значения в логическое (0 или 1 [BTW: нечисловые строки, например!!'abc'
, в этом случае становятся 0, и not NaN]) затем использует побитовую операцию ИЛИ для объединения битов.Похоже, это лучшая средняя производительность для всех браузеров (лучшая, по крайней мере, в Chrome и Firefox), но не самая быстрая во ВСЕХ из них. По какой-то причине тернарный оператор в IE работает быстрее.
п? п <0? -1: 1: 0
var s = n?n<0?-1:1:0;
По какой-то причине самый быстрый в IE.
jsPerf
Выполненные тесты: https://jsperf.com/get-sign-from-value
источник
Мои два цента с функцией, которая возвращает те же результаты, что и Math.sign, то есть sign (-0) -> -0, sign (-Infinity) -> -Infinity, sign (null) -> 0 , знак (не определено) -> NaN и т. д.
Jsperf не позволит мне создать тест или ревизию, извините за то, что не смог предоставить вам тесты (я попробовал jsbench.github.io, но результаты кажутся намного ближе друг к другу, чем с Jsperf ...)
Если бы кто-то мог добавить его в ревизию Jsperf, мне было бы любопытно посмотреть, как он сравнивается со всеми ранее предоставленными решениями ...
Спасибо!
Джим.
ИЗМЕНИТЬ :
Я должен был написать:
(
(+x && -1)
вместо(x && -1)
) дляsign('abc')
правильной обработки (-> NaN)источник
Math.sign не поддерживается в IE 11. Я комбинирую лучший ответ с ответом Math.sign:
Теперь можно напрямую использовать Math.sign.
источник