468 votes

Existe-t-il une fonction standard de signe (signum, sgn) en C/C++ ?

Je veux une fonction qui renvoie -1 pour les nombres négatifs et +1 pour les nombres positifs. http://en.wikipedia.org/wiki/Sign_function Il est assez facile d'écrire mon propre code, mais il semble que ce soit quelque chose qui devrait se trouver quelque part dans une bibliothèque standard.

Edit : Plus précisément, je cherchais une fonction fonctionnant sur les flottants.

21 votes

Que doit-il retourner pour 0 ?

78 votes

@Craig McQueen ; cela dépend si c'est un zéro positif ou un zéro négatif.

1 votes

J'ai remarqué que vous avez spécifié la valeur de retour comme un nombre entier. Cherchez-vous une solution qui prend des entiers ou des nombres à virgule flottante ?

1voto

khkarens Points 226

Vous pouvez utiliser boost::math::sign() méthode de boost/math/special_functions/sign.hpp si le boost est disponible.

0 votes

Notez que cela a été suggéré auparavant : stackoverflow.com/a/16869019/1187415 .

0 votes

Boost n'est pas une bibliothèque standard et certains d'entre nous ne sont pas autorisés à utiliser Boost pour leurs projets.

0voto

cheshirekow Points 1511

La question de l'OP était "C/C++" mais voici une solution strictement c++ :

template <typename T>
T sign(T t) 
{
    if( t == 0 )
        return T(0);
    else
        return (t < 0) : T(-1) : T(1);
}

qui ne gère pas le +/- zéro, mais qui utilise les templates de façon agréable pour surcharger tout type pour lequel le compilateur peut comprendre 0, 1 et -1. Si elle est utilisée sur un type pour lequel ce n'est pas vrai, alors le compilateur se plaindra afin que vous n'ayez pas un comportement inattendu. Cela n'aura pas la vitesse de certains des postes précédents, mais sera pratique pour de nombreux cas encore.

0voto

mrclng Points 136

Bien que la solution pour les nombres entiers dans la réponse acceptée soit assez élégante, le fait qu'elle ne puisse pas renvoyer NAN pour les types doubles m'a dérangé, aussi je l'ai légèrement modifiée.

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

Notez que le retour d'un NAN en virgule flottante, par opposition à un NAN codé en dur, est une bonne chose. NAN fait en sorte que le bit de signe soit activé dans certaines mises en œuvre donc la sortie pour val = -NAN y val = NAN seront identiques quoi qu'il arrive (si vous préférez une " nan " sur une -nan vous pouvez mettre un abs(val) avant le retour...)

0voto

Serge Rogatch Points 18

Voici une implémentation favorable aux branchements :

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

À moins que vos données ne comportent des zéros dans la moitié des nombres, le prédicteur de branche choisira l'une des branches comme étant la plus commune. Les deux branches n'impliquent que des opérations simples.

Alternativement, sur certains compilateurs et architectures de CPU, une version complètement sans branche peut être plus rapide :

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

Cela fonctionne pour Format de virgule flottante binaire double précision IEEE 754 : binary64 .

-1voto

Gigi Points 2858
int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

Cette fonction suppose :

  • binaire32 représentation des nombres à virgule flottante
  • un compilateur qui fait un exception concernant l'aliasing strict lors de l'utilisation d'un nommé syndicat

3 votes

Il y a encore de mauvaises hypothèses ici. Par exemple, je ne crois pas que l'endiveté d'un flottant soit garantie comme celle d'un entier. Votre vérification échoue également sur toutes les architectures utilisant ILP64. En réalité, vous réimplémentez juste copysign ; si vous utilisez static_assert vous avez C++11, et vous pourriez aussi bien utiliser vraiment copysign .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X