2008-09-15 9 views

Antwort

42

Hier ist eine Version, die in C/C++ arbeitet, die nicht auf ganzzahlige Größen angewiesen ist oder das Überlaufproblem haben (dh x * y> = 0 nicht funktioniert)

bool SameSign(int x, int y) 
{ 
    return (x >= 0)^(y < 0); 
} 

Natürlich Sie können und Vorlage Aussenseiter:

template <typename valueType> 
bool SameSign(typename valueType x, typename valueType y) 
{ 
    return (x >= 0)^(y < 0); 
} 

Hinweis: Da wir ausschließlich oder verwenden, wir wollen, dass die LHS und die RHS, anders zu sein, wenn die Vorzeichen gleich sind, so dass die unterschiedliche Prüfung gegen Null.

+1

Ganz nett, der C/C++ - Hacker in mir unterstützt dieses Code-Snippet vollständig. Der Softwareingenieur in mir fragt, warum der Benutzer dies in einer generischen Weise wissen muss! – user7116

+0

Schlägt dies nicht fehl, wenn x = 0 und y> 0 ist? –

2

if (x * y)> 0 ...

ungleich Null und eine solche anzunehmen.

1

Direkt an der Spitze von meinem Kopf ...

int mask = 1 << 31; 
(a & mask)^(b & mask) < 0; 
+0

funktioniert nur für 32-Bit-Ints, die nicht –

0

wenn (a * b < 0) Zeichen anders, sonst Zeichen gleich sind (oder a oder b ist Null)

+0

in der Frage festgelegt wurde, stimmt für den Schwall –

6

Unter der Annahme, 32-Bit-Ganzzahlen:

bool same = ((x^y) >> 31) != 1; 

etwas mehr terse:

bool same = !((x^y) >> 31); 
+2

Diese beiden Codebeispiele sollten immer immer immer durch einen Code Kommentar vorangestellt werden nicht funktionieren, bitte (im wirklichen Leben) –

+3

Oh, natürlich . Im wirklichen Leben würde ich wahrscheinlich etwas Ähnliches verwenden = Math.Sign (x) == Math.Sign (y). Ich gebe nur böse Bitwidilösungen, wenn Leute danach fragen. : D – Patrick

+1

Ähm, das ist kein gültiger Code ... wie soll '' 'funktionieren? –

0

Denken Sie zurück zu meinen Universitätstagen, in den meisten Maschinendarstellungen, ist nicht das äußerste linke Bit einer ganzen Zahl a 1, wenn die Zahl negativ ist, und 0, wenn es positiv ist?

Ich stelle mir vor, dass dies eher maschinenabhängig ist.

4

(integer1 * integer2)> 0

Denn wenn zwei ganzen Zahlen ein Zeichen teilen, wird immer das Ergebnis der Multiplikation positiv sein.

Sie können es auch> = 0 machen, wenn Sie 0 als gleiches Zeichen behandeln wollen, egal was passiert.

+2

Funktioniert nur bis das Produkt überläuft. – Frosty

+1

auch, Multiplikation könnte eher langsam sein ... –

+0

Wenn eine der ganzen Zahlen 0 sind, dann haben Sie ein Problem. – TatiOverflow

0

int gleich_sign =! ((X >> 31)^(y >> 31));

if (same_sign) ... sonst ...

2

Als technischer Hinweis, Bit-twiddly Lösungen werden wesentlich effizienter als Multiplikation sein, auch auf modernen Architekturen. Es ist nur etwa 3 Zyklen, die Sie speichern, aber Sie wissen, was sie von einem „Penny gespeichert“ sagen ...

+5

Ein gesparter Penny ist die Wurzel allen Übels, sagen wir etwa 97% der Zeit? – ysth

18
(a^b) >= 0 

zu 1 bewerten, wenn das Vorzeichen gleich, sonst 0 ist.

+0

Oh, schön! :-) Ich bin überrascht, dass ich diese verpasst habe. Das wirklich Schöne an dieser Lösung ist, dass sie nicht von einer bestimmten Bit-Kardinalität in der zugrundeliegenden Integer-Darstellung abhängt. –

+1

Dies führt zu der herrlich kompakten "xorl% edi,% esi; setzt% al" auf x86, nur 6 Bytes und zwei Anweisungen. Es ist auch eine interessante Fallstudie, da es sich um einen konkreten Fall handelt, in dem die Rückgabe eines "Bool" anstelle eines Int einen dramatisch besseren Code liefert. –

+0

@JohnMeacham: Ich frage mich, was Sie meinen, es ist ein konkreter Fall, in dem die Rückgabe eines 'Bool' anstelle eines Int einen dramatisch besseren Code ergibt. ' –

11

Ich wäre vorsichtig mit irgendwelchen bitweisen Tricks, um das Vorzeichen von ganzen Zahlen zu bestimmen, da dann Annahmen getroffen werden müssen, wie diese Zahlen intern dargestellt werden.

Fast 100% der Zeit, werden ganze Zahlen als two's compliment gespeichert werden, aber es ist keine gute Praxis Annahmen über die Interna eines System zu machen, wenn Sie einen Datentyp, der ein bestimmtes Speicherformat guarentees verwenden.

Im Zweierkomplement können Sie einfach das letzte (am weitesten links liegende) Bit in der ganzen Zahl überprüfen, um festzustellen, ob es negativ ist, so dass Sie nur diese zwei Bits vergleichen können. Dies würde bedeuten, dass 0 das gleiche Vorzeichen haben würde wie eine positive Zahl, was im Widerspruch zu der Zeichenfunktion steht, die in den meisten Sprachen implementiert ist.

Persönlich würde ich nur die Zeichenfunktion der von Ihnen gewählten Sprache verwenden. Es ist unwahrscheinlich, dass es bei einer Berechnung wie dieser Leistungsprobleme geben würde.

+0

Auch diese Tricks beeinträchtigen die Lesbarkeit. – hop

+1

Die C Standard Lib bietet eine signbit() -Funktion. Wahrscheinlich schwer, den Optimierer mit irgendwelchen "bitweisen Tricks" Ihrer eigenen Entwicklung zu übertreffen. – hop

1

Für jede Größe von int mit Komplement-Arithmetik der beiden:

#define SIGNBIT (~((unsigned int)-1 >> 1)) 
if ((x & SIGNBIT) == (y & SIGNBIT)) 
    // signs are the same 
1

unter der Annahme, 32-Bit-

if (((x^y) & 0x80000000) == 0)

... die antwort if (x * y> 0) ist schlecht wegen überlauf

5

ich bin mir nicht wirklich sicher ob ich "bitweises trick" und "einfachste" auch bedenke. Ich sehe viele Antworten, die signierte 32-Bit-Ganzzahlen annehmen (obwohl es würde albern sein, nach unsigned zu fragen); Ich bin nicht sicher, ob sie sich auf Fließkommawerte beziehen würden.

Es scheint, als wäre die "einfachste" Überprüfung, zu vergleichen, wie beide Werte mit 0 verglichen werden; Das ist ziemlich allgemein die Typen verglichen werden kann unter der Annahme:

bool compare(T left, T right) 
{ 
    return (left < 0) == (right < 0); 
} 

Wenn die Vorzeichen entgegengesetzt sind, erhalten Sie falsch. Wenn die Zeichen die gleichen sind, werden Sie wahr.

+0

false && false == false Ich befürchte, dass Sie die Negation eines XOR machen müssen, um es korrekt zu machen. –

187

Was mit

return ((x<0) == (y<0)); 

falsch?

+21

Um ... Nichts ... Traurig, dass wir alle die einfache Lösung verpasst haben. – Torlack

+0

Große Antwort, Einfachheit ist wunderbar. –

+1

Was ist mit Signed Zero. -0.0 vs Unsigned Null 0.0 –

4

Unter der Annahme, Zweier-Komplement-Arithmetik (http://en.wikipedia.org/wiki/Two_complement):

inline bool same_sign(int x, int y) { 
    return (x^y) >= 0; 
} 

Dies kann so wenig wie zwei Befehle nehmen und weniger als 1 ns auf einem modernen Prozessor mit Optimierung.

nicht davon aus Zweier-Komplement-Arithmetik:

inline bool same_sign(int x, int y) { 
    return (x<0) == (y<0); 
} 

Diese eine oder zwei zusätzliche Anweisungen erfordern und ein wenig länger dauern.

Die Verwendung von Multiplikation ist eine schlechte Idee, da sie anfällig für Überlauf ist.

+0

1 und 0 ist wahr für beide Funktionen ... – matias

+1

@matias Wie es sollte. 0 und 1 haben das gleiche Vorzeichen. Ganzzahlen haben keine negative 0. –

+0

offensichtlich haben Sie Recht, ich habe total Hirn gefurzt – matias

1

branchless C-Version:

int sameSign(int a, int b) { 
    return ~(a^b) & (1<<(sizeof(int)*8-1)); 
} 

C++ Vorlage für Integer-Typen:

template <typename T> T sameSign(T a, T b) { 
    return ~(a^b) & (1<<(sizeof(T)*8-1)); 
} 
0

bessere Art und Weise std::signbit wie folgt verwendet:

std::signbit(firstNumber) == std::signbit(secondNumber); 

es auch andere Grundtypen unterstützen (double , float, char etc).

Verwandte Themen