Существует ли стандартная функция знака (signum, sgn) в C / C ++? - PullRequest
371 голосов
/ 15 декабря 2009

Мне нужна функция, которая возвращает -1 для отрицательных чисел и +1 для положительных чисел. http://en.wikipedia.org/wiki/Sign_function Достаточно легко написать свою собственную, но кажется, что-то, что должно быть где-то в стандартной библиотеке.

Редактировать: В частности, я искал функцию, работающую с плавающей точкой.

Ответы [ 23 ]

4 голосов
/ 15 декабря 2009

Моя копия C в двух словах показывает существование стандартной функции copysign, которая может быть полезна. Похоже, что copysign (1.0, -2.0) вернет -1.0, а copysign (1.0, 2.0) вернет + 1.0.

Довольно близко, да?

3 голосов
/ 11 июля 2014

Нет, его нет в c ++, как в matlab. Для этого я использую макрос в своих программах.

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )
3 голосов
/ 13 января 2017

Принятый ответ с приведенной ниже перегрузкой действительно не вызывает -Wtype-limit .

template <typename T> inline constexpr
  int signum(T x, std::false_type) {
  return T(0) < x;
}

template <typename T> inline constexpr
  int signum(T x, std::true_type) {
  return (T(0) < x) - (x < T(0));
}

template <typename T> inline constexpr
  int signum(T x) {
  return signum(x, std::is_signed<T>());
}

Для C ++ 11 альтернативой может быть.

template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T x) {
    return T(0) < x;  
}

template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T x) {
    return (T(0) < x) - (x < T(0));  
}

Для меня это не вызывает никаких предупреждений в GCC 5.3.1.

1 голос
/ 29 августа 2018

Вы можете использовать метод boost::math::sign() из boost/math/special_functions/sign.hpp, если доступно повышение.

1 голос
/ 15 июля 2017

Немного не по теме, но я использую это:

template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
    return (a > b) - (a < b);
}

template<typename T>
constexpr int sgn(const T &a) noexcept{
    return sgn(a, T(0));
}

и я обнаружил, что первая функция - с двумя аргументами - гораздо более полезна из "стандартного" sgn (), потому что она чаще всего используется в таком коде:

int comp(unsigned a, unsigned b){
   return sgn( int(a) - int(b) );
}

против

int comp(unsigned a, unsigned b){
   return sgn(a, b);
}

нет броска для неподписанных типов и без дополнительного минуса.

на самом деле у меня есть этот кусок кода с использованием sgn ()

template <class T>
int comp(const T &a, const T &b){
    log__("all");
    if (a < b)
        return -1;

    if (a > b)
        return +1;

    return 0;
}

inline int comp(int const a, int const b){
    log__("int");
    return a - b;
}

inline int comp(long int const a, long int const b){
    log__("long");
    return sgn(a, b);
}
0 голосов
/ 19 ноября 2018

Вот реализация для ветвления:

inline int signum(const double x) {
    if(x == 0) return 0;
    return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

Если ваши данные не имеют нулей в качестве половины чисел, здесь предиктор ветвей выберет одну из ветвей в качестве наиболее распространенной. Обе ветви включают только простые операции.

В качестве альтернативы, на некоторых компиляторах и архитектурах ЦП версия без ответвлений может быть быстрее:

inline int signum(const double x) {
    return (x != 0) * 
        (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

Это работает для двоичного формата с плавающей точкой двойной точности IEEE 754: binary64 .

0 голосов
/ 30 июня 2018

Зачем использовать троичные операторы и если-иначе, когда вы можете просто сделать это

#define sgn(x) x==0 ? 0 : x/abs(x)
0 голосов
/ 16 ноября 2017

использование:

`#define sgn(x) (x<0)` 

например:

`if(sng(n)) { etc ....}`

Или, возможно, вы захотите использовать какой-то сложный код, но сначала выполните приведение:

inline bool sgn_long(long x) { return ((x<0)? true: false); }

0 голосов
/ 11 августа 2017

Хотя целочисленное решение в принятом ответе довольно элегантно, меня беспокоило, что оно не сможет вернуть NAN для двойных типов, поэтому я немного его изменил.

template <typename T> double sgn(T val) {
    return double((T(0) < val) - (val < T(0)))/(val == val);
}

Обратите внимание, что при возврате NAN с плавающей точкой в ​​отличие от жестко заданного NAN в устанавливается бит знака в некоторых реализациях , поэтому вывод для val = -NAN и val = NAN будет быть идентичным независимо от того, что (если вы предпочитаете вывод "nan" вместо -nan, вы можете поставить abs(val) перед возвратом ...)

0 голосов
/ 22 мая 2017

А как же:

int sgn = x/fabs(x);

должно получиться неплохо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...