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?

5voto

Mein Exemplar von C in a Nutshell zeigt die Existenz einer Standardfunktion namens copysign, die nützlich sein könnte. Es sieht so aus, als würde copysign(1.0, -2.0) -1.0 und copysign(1.0, 2.0) +1.0 zurückgeben.

Ziemlich nah dran, was?

0 Stimmen

Nicht Standard, aber möglicherweise weithin verfügbar. Microsofts beginnt mit einem Unterstrich, das ist die Konvention, die sie für nicht standardisierte Erweiterungen verwenden. Allerdings nicht die beste Wahl, wenn Sie mit ganzen Zahlen arbeiten.

6 Stimmen

Copysign ist sowohl in den ISO C (C99) als auch in den POSIX-Standards enthalten. Siehe opengroup.org/onlinepubs/000095399/functions/copysign.html

3 Stimmen

Wie lhf sagte. Visual Studio ist nicht eine Referenz für den C-Standard.

4voto

SamVanDonut Punkte 351

Die akzeptierte Antwort mit der nachstehenden Überlast löst tatsächlich nicht aus -Wtype-limits . Aber es löst aus ungenutztes Argument Warnungen (auf der is_signed Variable). Um dies zu vermeiden, sollte das zweite Argument nicht so benannt werden:

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

Für C++11 und höher könnte eine Alternative sein.

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

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

Bei mir löst es keine Warnungen auf GCC 5.3.1 aus.

0 Stimmen

Zur Vermeidung der -Wunused-parameter Warnung nur unbenannte Parameter verwenden.

0 Stimmen

Das ist tatsächlich sehr wahr. Das habe ich übersehen. Allerdings gefällt mir die C++11-Alternative so oder so besser.

4voto

Antonin GAVREL Punkte 7751

Die Frage ist alt, aber es gibt jetzt diese Art der gewünschten Funktion. Ich habe einen Wrapper mit not, left shift und dec hinzugefügt.

Sie können eine Wrapper-Funktion verwenden, die auf Vorzeichen aus C99 um genau das gewünschte Verhalten zu erreichen (siehe Code weiter unten).

Gibt zurück, ob das Vorzeichen von x negativ ist.
Dies kann auch auf Unendlichkeiten, NaNs und Nullen angewandt werden (wenn die Null vorzeichenlos ist, wird sie als positiv betrachtet).

#include <math.h>

int signValue(float a) {
    return ((!signbit(a)) << 1) - 1;
}

NB: Ich verwende den Operanden not ("!"), weil der Rückgabewert von signbit nicht 1 sein soll (auch wenn die Beispiele vermuten lassen, dass es immer so ist), sondern wahr für eine negative Zahl:

Rückgabewert
Ein Wert ungleich Null (wahr), wenn das Vorzeichen von x negativ ist; andernfalls Null (falsch).

Dann multipliziere ich mit zwei mit Linksverschiebung (" << 1"), was uns 2 für eine positive Zahl und 0 für eine negative Zahl ergibt, und schließlich dekrementiere ich um 1, um 1 und -1 für positive bzw. negative Zahlen zu erhalten, wie von OP gewünscht.

1 Stimmen

0 wird dann auch positiv sein... was vielleicht auch nicht das ist, was OP wollte...

0 Stimmen

Nun, wir werden wohl nie erfahren, was OP wirklich wollte, wenn n=0... !

3voto

khkarens Punkte 1195

Sie können verwenden boost::math::sign() Methode von boost/math/special_functions/sign.hpp wenn Boost verfügbar ist.

0 Stimmen

Beachten Sie, dass dies bereits früher vorgeschlagen wurde: stackoverflow.com/a/16869019/1187415 .

2 Stimmen

Boost ist keine Standardbibliothek und einige von uns dürfen Boost nicht für ihre Projekte verwenden.

2voto

chattering Punkte 63

Nein, das gibt es in C++ nicht, so wie in Matlab. Ich verwende dafür ein Makro in meinen Programmen.

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )

6 Stimmen

In C++ sollte man Templates den Makros vorziehen.

0 Stimmen

0 Stimmen

Ich dachte, das sei eine gute Antwort, dann sah ich mir meinen eigenen Code an und fand dies: #define sign(x) (((x) > 0) - ((x) < 0)) was auch gut ist.

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