
bekloppt
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 eigenen zu schreiben, aber es scheint etwas zu sein, das irgendwo in einer Standardbibliothek enthalten sein sollte.
Bearbeiten: Insbesondere suchte ich nach einer Funktion, die mit Floats arbeitet.
Die typsichere C++-Version:
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
Leistungen:
- Implementiert tatsächlich signum (-1, 0 oder 1). Implementierungen hier, die copysign verwenden, geben nur -1 oder 1 zurück, was nicht signum ist. Außerdem geben einige Implementierungen hier einen Float (oder T) anstelle eines Int zurück, was verschwenderisch erscheint.
- Funktioniert für Ints, Floats, Doubles, unsigned Shorts oder alle benutzerdefinierten Typen, die aus Integer 0 konstruierbar und bestellbar sind.
- Schnell!
copysign
ist langsam, besonders wenn Sie fördern und dann wieder verengen müssen. Diese ist verzweigt und optimiert hervorragend
- Normgerecht! Der Bitshift-Hack ist ordentlich, funktioniert aber nur für einige Bitdarstellungen und funktioniert nicht, wenn Sie einen unsignierten Typ haben. Es könnte gegebenenfalls als manuelle Spezialisierung angeboten werden.
- Genau! Einfache Vergleiche mit Null können die interne hochpräzise Darstellung der Maschine (z. B. 80 Bit auf x87) beibehalten und ein vorzeitiges Runden auf Null vermeiden.
Vorbehalte:
-
Da es sich um eine Vorlage handelt, kann die Kompilierung unter Umständen länger dauern.
-
Anscheinend denken einige Leute an die Verwendung einer neuen, etwas esoterischen und sehr langsamen Standardbibliotheksfunktion das implementiert signum nicht einmal wirklich ist verständlicher.
-
Die < 0
Ein Teil der Prüfung löst GCCs aus -Wtype-limits
Warnung bei Instanziierung für einen unsignierten Typ. Sie können dies vermeiden, indem Sie einige Überladungen verwenden:
template <typename T> inline constexpr
int signum(T x, std::false_type is_signed) {
return T(0) < x;
}
template <typename T> inline constexpr
int signum(T x, std::true_type is_signed) {
return (T(0) < x) - (x < T(0));
}
template <typename T> inline constexpr
int signum(T x) {
return signum(x, std::is_signed<T>());
}
(Was ein gutes Beispiel für den ersten Vorbehalt ist.)

Markus Byers
Mir ist keine Standardfunktion dafür bekannt. Hier ist eine interessante Art, es zu schreiben:
(x > 0) - (x < 0)
Hier ist ein besser lesbarer Weg, dies zu tun:
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
Wenn Sie den ternären Operator mögen, können Sie dies tun:
(x > 0) ? 1 : ((x < 0) ? -1 : 0)

kommender Sturm
Es gibt eine mathematische C99-Bibliotheksfunktion namens copysign(), die das Vorzeichen von einem Argument und den absoluten Wert von dem anderen übernimmt:
result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double
ergibt je nach Wertvorzeichen ein Ergebnis von +/- 1,0. Beachten Sie, dass Gleitkomma-Nullen vorzeichenbehaftet sind: (+0) ergibt +1 und (-0) ergibt -1.

Katzenkul
Es scheint, dass die meisten Antworten die ursprüngliche Frage verfehlt haben.
Gibt es eine Standardzeichenfunktion (signum, sgn) in C/C++?
Nicht in der Standardbibliothek, aber es gibt copysign
die fast genauso verwendet werden kann via copysign(1.0, arg)
und es gibt eine wahre Vorzeichenfunktion boost
was auch zum Standard gehören könnte.
#include <boost/math/special_functions/sign.hpp>
//Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
template <class T>
inline int sign (const T& z);
http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html
Anscheinend lautet die Antwort auf die Frage des ursprünglichen Posters nein. Es gibt kein Standard C++ sgn
Funktion.
Gibt es eine Standardzeichenfunktion (signum, sgn) in C/C++?
Ja, je nach Definition.
C99 und höher hat die signbit()
Makro ein <math.h>
int signbit
(echt schwebend x
);
Die signbit
Das Makro gibt genau dann einen Wert ungleich Null zurück, wenn das Vorzeichen seines Argumentwerts negativ ist. C11 §7.12.3.6
Doch OP will etwas anderes.
Ich möchte eine Funktion, die -1 für negative Zahlen und +1 für positive Zahlen zurückgibt. … eine Funktion, die mit Floats arbeitet.
#define signbit_p1_or_n1(x) ((signbit(x) ? -1 : 1)
Tiefer:
Die Frage von OP ist in den folgenden Fällen nicht spezifisch: x = 0.0, -0.0, +NaN, -NaN
.
Ein Klassiker signum()
kehrt zurück +1
an x>0
, -1
an x<0
und 0
an x==0
.
Viele Antworten haben das bereits abgedeckt, aber nicht angesprochen x = -0.0, +NaN, -NaN
. Viele sind auf eine ganzzahlige Sichtweise ausgerichtet, der normalerweise Not-a-Numbers (NaN) und -0,0.
Typische Antworten funktionieren wie signnum_typical()
An -0.0, +NaN, -NaN
sie kehren zurück 0.0, 0.0, 0.0
.
int signnum_typical(double x) {
if (x > 0.0) return 1;
if (x < 0.0) return -1;
return 0;
}
Stattdessen schlage ich diese Funktionalität vor: Ein -0.0, +NaN, -NaN
es kehrt zurück -0.0, +NaN, -NaN
.
double signnum_c(double x) {
if (x > 0.0) return 1.0;
if (x < 0.0) return -1.0;
return x;
}

Tim Cooper
Schneller als die oben genannten Lösungen, einschließlich der am besten bewerteten:
(x < 0) ? -1 : (x > 0)
9927100cookie-checkGibt es eine Standardzeichenfunktion (signum, sgn) in C/C++?yes
Was soll es für 0 zurückgeben?
– Craig McQueen
14. Dezember 2009 um 23:26 Uhr
@Craig McQueen; das hängt davon ab, ob es sich um eine positive Null oder eine negative Null handelt.
– ysth
15. Dezember 2009 um 5:53 Uhr
@ysth @Craig McQueen, falsch auch für Floats, oder? sgn(x)s Definition sagt, 0 zurückzugeben, wenn
x==0
. Entsprechend IEEE754negative Null und positive Null sollten gleich sein.– RJFalconer
4. Juni 2014 um 11:28 Uhr
@ysth “es hängt von positiver Null oder negativer Null ab”. In der Tat nicht.
– RJFalconer
6. Juni 2014 um 8:10 Uhr
Spät kommentiert, aber in Bezug auf vorzeichenbehaftete Nullen ist eine andere vernünftige Option, dass sgn(x) x zurückgibt, wenn x Null ist. Mit anderen Worten, Sie erhalten 0 heraus, aber es ist eine vorzeichenbehaftete Null mit demselben Vorzeichen wie die Eingabe. @RJFalconer In den relativ wenigen Fällen, in denen vorzeichenbehaftete Nullen eine Rolle spielen, erhalten Sie eine vernünftige Antwort, und in den anderen Fällen macht es keinen Unterschied.
– Backstein
15. Februar 2018 um 19:14 Uhr