Интересно, существуют ли какие-либо нетривиальные способы нахождения знака числа (функция 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. Использование бит-сдвига
быстро, но sign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Тип-безопасный [мегафаст]
! Кажется, что браузеры (особенно хром v8) делают некоторые магические оптимизации, и это решение оказывается намного более результативным, чем другие, даже чем (1.1), несмотря на то, что оно содержит 2 дополнительных операции и логически никогда не может быть быстрее.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Инструменты
Усовершенствования приветствуются!
[Offtopic] Принятый ответ
-
Андрей Таранцов - +100 для искусства, но, к сожалению, он примерно в 5 раз медленнее, чем очевидный подход
-
Frédéric Hamidi - как-то самый лучший ответ (для написания времени), и это довольно круто, но определенно не так, как должно быть сделано, imho, Также он неправильно обрабатывает номера бесконечности, которые также являются числами.
-
kbec - это улучшение очевидного решения. Не то, что революционер, но, взяв все вместе, я считаю этот подход лучшим. Голосуйте за него:)
Ответ 1
Более элегантная версия быстрого решения:
var sign = number?number<0?-1:1:0
Ответ 2
Деление числа на его абсолютное значение также дает свой знак. Использование короткого замыкания логического оператора И позволяет нам делать особый случай 0
, поэтому мы не делим его на него:
var sign = number && number / Math.abs(number);
Ответ 3
Функция, которую вы ищете, называется signum, и лучший способ ее реализовать:
function sgn(x) {
return (x > 0) - (x < 0);
}
Ответ 4
Если это не поддерживает JavaScripts (ECMAScripts), подписанные нулями? Кажется, он работает при возврате x вместо 0 в функцию "мегафаст":
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}
Это делает его совместимым с черновиком ECMAScripts Math.sign (MDN):
Возвращает знак x, указывающий, является ли x положительным, отрицательным или нулевым.
- Если x является NaN, результатом является NaN.
- Если x равно -0, результат равен -0.
- Если x равно +0, результат равен +0.
- Если x отрицательно, а не -0, результат равен -1.
- Если x положительно, а не +0, результат равен +1.
Ответ 5
Для тех, кому интересно, что происходит с последними браузерами, в версии ES6 существует собственный метод Math.sign. Здесь вы можете проверить поддержку .
В основном он возвращает -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
Ответ 6
var sign = number >> 31 | -number >>> 31;
Superfast, если вам не нужна бесконечность, и знайте, что число является целым числом, найденным в источнике openjdk-7: java.lang.Integer.signum()
Ответ 7
Я думал, что добавлю это просто для удовольствия:
function sgn(x){
return 2*(x>0)-1;
}
0 и NaN вернет -1
отлично работает на +/- Бесконечность
Ответ 8
Решение, которое работает во всех числах, а также 0
и -0
, а также Infinity
и -Infinity
:
function sign( number ) {
return 1 / number > 0 ? 1 : -1;
}
Для получения дополнительной информации см. вопрос "+0 и -0 то же?".
Предупреждение: Ни один из этих ответов, включая стандартный Math.sign
, не будет работать в случае 0
vs -0
. Это может не быть проблемой для вас, но в некоторых реализациях физики это может иметь значение.
Ответ 9
Вы можете поменять число и проверить самый значительный бит (MSB). Если MSB равен 1, то число отрицательно. Если это 0, то число положительно (или 0).
Ответ 10
Я только собирался задать тот же вопрос, но пришел к решению, прежде чем я закончил писать, увидел, что этот вопрос уже существует, но не видел этого решения.
(n >> 31) + (n > 0)
кажется, быстрее, добавив тройной, хотя (n >> 31) + (n>0?1:0)
Ответ 11
Очень похоже на ответ Martijn
function sgn(x) {
isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1));
}
Я считаю его более читаемым. Также (или, в зависимости от вашей точки зрения, однако), он также анализирует вещи, которые можно интерпретировать как число; например, он возвращает -1
при представлении '-5'
.
Ответ 12
Я не вижу практического смысла возврата -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
Ответ 13
Методы, о которых я знаю, следующие:
Math.sign(п)
var s = Math.sign(n)
Это нативная функция, но самая медленная из-за накладных расходов на вызов функции. Однако он обрабатывает "NaN", где остальные ниже могут просто принять 0 (то есть Math.sign('abc') является NaN).
((n > 0) - (n < 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. В правой части |
он проверяет положительный результат, преобразовывая значение в значение boolean (0 или 1 [BTW: нечисловые строки, например !!'abc'
), становятся 0 в этом случае, а не 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
Ответ 14
Мои два цента с функцией, которая возвращает те же результаты, что и Math.sign, т.е. знак (-0) → -0, знак (-Infinity) → -Infinity, знак (null) → 0, знак (неопределенный) → NaN и т.д.
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)