519 Stimmen

Gibt es eine Standard-Vorzeichenfunktion (signum, sgn) in C/C++?

Ich möchte eine Funktion, die -1 für negative Zahlen und +1 für positive Zahlen zurückgibt. http://en.wikipedia.org/wiki/Sign_function Es ist einfach genug, meine eigene zu schreiben, aber es scheint etwas zu sein, das irgendwo in einer Standardbibliothek sein sollte.

Edit: Ich habe speziell nach einer Funktion gesucht, die mit Floats arbeitet.

28 Stimmen

Was sollte er für 0 zurückgeben?

91 Stimmen

@Craig McQueen; das hängt davon ab, ob es sich um eine positive Null oder eine negative Null handelt.

1 Stimmen

Mir ist aufgefallen, dass Sie den Rückgabewert als Ganzzahl angegeben haben. Suchen Sie nach einer Lösung, die Ganzzahlen oder Fließkommazahlen verarbeitet?

2voto

Nick Punkte 8893

Ein bisschen off-topic, aber ich benutze das:

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));
}

und ich fand die erste Funktion - die mit zwei Argumenten - sehr viel nützlicher als die "Standard"-Funktion sgn(), weil sie am häufigsten in Code wie diesem verwendet wird:

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

vs.

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

gibt es keinen Cast für vorzeichenlose Typen und kein zusätzliches Minus.

In der Tat habe ich dieses Stück Code mit 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);
}

1voto

Serge Rogatch Punkte 12301

Hier ist eine verzweigungsfreundliche Implementierung:

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

Sofern Ihre Daten nicht zur Hälfte aus Nullen bestehen, wählt der Zweigprädiktor einen der Zweige als den häufigsten aus. Beide Zweige beinhalten nur einfache Operationen.

Alternativ dazu kann bei einigen Compilern und CPU-Architekturen eine vollständig verzweigungslose Version schneller sein:

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

Dies funktioniert bei IEEE 754 doppeltgenaues binäres Gleitkommaformat: binary64 .

0voto

mrclng Punkte 444

Während die Integer-Lösung in der akzeptierten Antwort recht elegant ist, störte es mich, dass sie nicht in der Lage ist, NAN für Double-Typen zurückzugeben, also habe ich sie leicht verändert.

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

Beachten Sie, dass die Rückgabe einer Fließkomma-NAN im Gegensatz zu einer hart kodierten NAN bewirkt, dass das Vorzeichenbit in einige Implementierungen , so dass die Ausgabe für val = -NAN y val = NAN werden auf jeden Fall identisch sein (wenn Sie eine " nan " Ausgabe über eine -nan können Sie eine abs(val) vor der Rückkehr...)

-1voto

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

Diese Funktion setzt voraus:

  • binär32 Darstellung von Gleitkommazahlen
  • einen Compiler, der eine Ausnahme über das strenge Aliasing Regel bei Verwendung einer namens Gewerkschaft

3 Stimmen

Hier gibt es noch einige falsche Annahmen. Zum Beispiel glaube ich nicht, dass die Endianness des Floats garantiert die Endianness des Integers ist. Ihre Prüfung schlägt auch auf allen Architekturen fehl, die ILP64 verwenden. Wirklich, Sie reimplementieren nur copysign ; wenn Sie mit static_assert Sie haben C++11, und Sie könnten auch wirklich die copysign .

-3voto

cyberion Punkte 41
double signof(double a) { return (a == 0) ? 0 : (a<0 ? -1 : 1); }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X