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?

49voto

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

Ja, je nach Definition.

C99 und später hat die signbit() Makro in <math.h>

int signbit (real-floating x );
Die signbit gibt nur dann einen Wert ungleich Null zurück, wenn das Vorzeichen des Argumentwerts negativ ist. C11 §7.12.3.6


Doch OP will etwas ganz anderes.

Ich möchte eine Funktion, die -1 für negative Zahlen und +1 für positive Zahlen zurückgibt. ... eine Funktion, die mit Gleitkommazahlen arbeitet.

#define signbit_p1_or_n1(x)  ((signbit(x) ?  -1 : 1)

Tiefer:

Die Frage des Auftraggebers ist in den folgenden Fällen nicht spezifisch: x = 0.0, -0.0, +NaN, -NaN .

Ein Klassiker signum() gibt zurück. +1 auf x>0 , -1 auf x<0 y 0 auf x==0 .

Viele Antworten haben dies bereits abgedeckt, gehen aber nicht darauf ein x = -0.0, +NaN, -NaN . Viele sind auf eine ganzzahlige Sichtweise ausgerichtet, die in der Regel keine Not-a-Numbers ( NaN ) und -0.0 .

Typische Antworten funktionieren wie signnum_typical() Auf -0.0, +NaN, -NaN kehren sie 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 Funktion vor: Auf -0.0, +NaN, -NaN gibt er 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;
}

1 Stimmen

Ah, genau das, was ich suche. Dies wurde gerade in Pharo Smalltalk geändert github.com/pharo-project/pharo/pull/1835 und ich habe mich gefragt, ob es eine Art Norm (IEC 60559 oder ISO 10967) gibt, die das Verhalten für negative Nullen und das Verhalten von Nan vorschreibt... Ich mag das Javascript-Zeichen developer.mozilla.org/de-US/docs/Web/JavaScript/Reference/

30voto

xnx Punkte 408

Schneller als die oben genannten Lösungen, einschließlich der am höchsten bewerteten Lösung:

(x < 0) ? -1 : (x > 0)

1 Stimmen

Welcher Typ ist x? Oder verwenden Sie ein #define?

3 Stimmen

Ihr Typ ist nicht schneller. Er wird ziemlich oft einen Cache-Miss verursachen.

20 Stimmen

Fehlt der Cache? Ich bin mir nicht sicher, wie. Vielleicht meinten Sie Verzweigungs-Fehlprognose?

17voto

Tim Sylvester Punkte 22343

Es gibt eine Möglichkeit, dies ohne Verzweigungen zu tun, aber das ist nicht sehr schön.

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));

http://graphics.stanford.edu/~seander/bithacks.html

Auf dieser Seite gibt es auch viele andere interessante, übermäßig clevere Dinge...

1 Stimmen

Wenn ich den Link richtig gelesen habe, gibt das nur -1 oder 0 zurück. Wenn Sie -1, 0 oder +1 wollen, dann ist es sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1)); o sign = (v > 0) - (v < 0); .

2 Stimmen

Dies bedeutet, dass v ein Integer-Typ ist, der nicht größer als int ist

13voto

ysth Punkte 91645

Wenn Sie nur das Vorzeichen testen wollen, verwenden Sie signbit (gibt true zurück, wenn sein Argument ein negatives Vorzeichen hat). Ich bin mir nicht sicher, warum Sie -1 oder +1 zurückgegeben haben wollen; copysign ist bequemer dafür, aber es klingt so, als ob es +1 für negative Null auf einigen Plattformen mit mit nur teilweiser Unterstützung für negative Nullen, wo signbit vermutlich true zurückgeben würde.

10 Stimmen

Es gibt viele mathematische Anwendungen, bei denen das Vorzeichen (x) notwendig ist. Sonst würde ich einfach machen if (x < 0) .

10voto

Tabernakel Punkte 111

Im Allgemeinen gibt es in C/C++ keine Standard-Signum-Funktion, und das Fehlen einer solchen grundlegenden Funktion sagt viel über diese Sprachen aus.

Abgesehen davon glaube ich, dass beide Mehrheitsmeinungen über den richtigen Ansatz zur Definition einer solchen Funktion in gewisser Weise richtig sind, und die "Kontroverse" darüber ist eigentlich ein Nicht-Argument, wenn man zwei wichtige Vorbehalte in Betracht zieht:

  • A Signum Funktion sollte immer den Typ ihres Operanden zurückgeben, ähnlich wie bei einer abs() Funktion, denn Signum wird in der Regel für die Multiplikation mit einem absoluten Wert verwendet, nachdem letzterer irgendwie verarbeitet wurde. Daher ist der Hauptanwendungsfall von Signum ist nicht Vergleiche, sondern Arithmetik, und letztere sollte keine teuren Integer-zu/aus Fließkomma-Umwandlungen beinhalten.

  • Bei Fließkommatypen gibt es keinen einzigen exakten Nullwert: +0,0 kann als "infinitesimal über Null" und -0,0 als "infinitesimal unter Null" interpretiert werden. Das ist der Grund, warum Vergleiche, die Null beinhalten, intern gegen beide Werte prüfen müssen, und ein Ausdruck wie x == 0.0 kann gefährlich sein.

Was C betrifft, so denke ich, dass der beste Weg nach vorne mit integralen Typen in der Tat die Verwendung der (x > 0) - (x < 0) Ausdruck, da er verzweigungsfrei übersetzt werden sollte und nur drei Grundoperationen erfordert. Definieren Sie am besten Inline-Funktionen, die einen Rückgabetyp erzwingen, der dem Argumenttyp entspricht, und fügen Sie ein C11 define _Generic um diese Funktionen auf einen gemeinsamen Namen abzubilden.

Bei Fließkommazahlen denke ich, dass Inline-Funktionen auf Basis von C11 copysignf(1.0f, x) , copysign(1.0, x) y copysignl(1.0l, x) sind der richtige Weg, einfach weil sie mit hoher Wahrscheinlichkeit auch verzweigungsfrei sind und außerdem kein Casting des Ergebnisses von Integer zurück in eine Fließkommazahl erfordern. Sie sollten wahrscheinlich an prominenter Stelle darauf hinweisen, dass Ihre Fließkomma-Implementierungen von Signum gibt wegen der Besonderheiten von Fließkomma-Nullwerten, aus Zeitgründen und weil es in der Fließkomma-Arithmetik oft sehr nützlich ist, auch für Nullwerte das richtige Vorzeichen -1/+1 zu erhalten, nicht Null zurück.

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