Number.sign () в JavaScript - PullRequest
       41

Number.sign () в JavaScript

99 голосов
/ 02 октября 2011

Интересно, есть ли нетривиальные способы нахождения знака числа ( функция знака )?
Может быть короче / быстрее / элегантнее решения, чем очевидное

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. Тип безопасности [мегафаст]

! Похоже, что браузеры (особенно 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 раз медленнее, чем очевидный подход

  • Фредерик Хамиди - каким-то образом самый одобренный ответ (на время написания), и это круто, но это определенно не то, как все должно быть сделано, имхо. Кроме того, он неправильно обрабатывает числа бесконечности, которые также являются числами.

  • kbec - улучшение очевидного решения. Не такой уж революционный, но, собрав все вместе, я считаю такой подход лучшим. Проголосуй за него:)

Ответы [ 14 ]

0 голосов
/ 30 ноября 2016

Я не вижу практического смысла возвращать -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
0 голосов
/ 15 мая 2014

Очень похоже на ответ Мартина:

function sgn(x) {
    isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1));
}

Я считаю его более читабельным.Также (или, в зависимости от вашей точки зрения, однако), он также поглощает вещи, которые можно интерпретировать как число;например, он возвращает -1, когда представлен '-5'.

0 голосов
/ 26 сентября 2013

Я только собирался задать тот же вопрос, но пришел к решению до того, как закончил писать, видел, что этот вопрос уже существует, но не видел этого решения.

(n >> 31) + (n > 0)

кажется, что быстрее, если добавить троичный, хотя (n >> 31) + (n>0?1:0)

0 голосов
/ 02 октября 2011

Вы можете сдвинуть бит числа и проверить самый старший бит (MSB). Если MSB равен 1, то число является отрицательным. Если это 0, то число является положительным (или 0).

...