Kann man zwischen 0 und -0 unterscheiden?


94

Ich weiß, dass die ganzzahligen Werte 0und -0im Wesentlichen gleich sind. Aber ich frage mich, ob es möglich ist, zwischen ihnen zu unterscheiden.

Woher weiß ich beispielsweise, ob eine Variable zugewiesen wurde -0?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

Ist der -0im Speicher gespeicherte Wert genauso wie 0?


9
Für ganze Zahlen gibt es keinen Unterschied.
Maroun

14
Dies hängt von der Implementierung ab, jedoch für Implementierungen, bei denen intdas Zweierkomplement dargestellt wird (bei weitem das am häufigsten anzutreffende) 0und -0die identische bitweise Darstellung aufweisen.
Mankarse

11
Auf einer 2er-Komplement-Maschine gibt es keinen Unterschied auf Bitebene.
Marco A.

17
@VirtualSnake: Was bedeutet "in binär"? Tatsächlich gibt es binäre Codierungen, bei denen beispielsweise zwischen -0 und 0 unterschieden wird. Vorzeichen und Größe.
Benjamin Lindley

8
@VirtualSnake Das stimmt, wir reden hier int. Siehe die Komplementcodierung von Ones .
CiaPan

Antworten:


112

Dies hängt von der Maschine ab, auf die Sie abzielen.

Auf einer Maschine, die eine 2er-Komplementdarstellung für Ganzzahlen verwendet, gibt es auf Bitebene keinen Unterschied zwischen 0und -0(sie haben dieselbe Darstellung).

Wenn Ihre Maschine die eigene Ergänzung verwendet , könnten Sie dies definitiv tun

0000 0000   -> signed0
1111 1111   -> signed   0

Offensichtlich geht es um die native Unterstützung . Prozessoren der x86-Serie bieten native Unterstützung für die komplementäre Darstellung von vorzeichenbehafteten Zahlen. Die Verwendung anderer Darstellungen ist definitiv möglich, wäre jedoch wahrscheinlich weniger effizient und erfordert mehr Anweisungen.

(Wie JerryCoffin auch bemerkte: Auch wenn das eigene Komplement hauptsächlich aus historischen Gründen betrachtet wurde, sind vorzeichenbehaftete Größenrepräsentationen immer noch ziemlich häufig und haben eine separate Darstellung für negative und positive Nullen.)


6
@TobiMcNamobi: Nicht wahrscheinlich genug, um jemals besorgt zu sein. Es würde mich wundern, wenn sich jemals jemand die Mühe gemacht hätte, einen C ++ - Compiler zu portieren, um eine Ausgabe für eine solche Maschine zu erzeugen.
Benjamin Lindley

1
Ich stimme Benjamin zu, historisch gesehen gab es Maschinen, die es verwendeten, aber heutzutage kenne ich keine Produktionsmaschinen, die es verwenden. Trotzdem ist es immer gut zu wissen und im Auge zu behalten.
Marco A.

4
@TobiMcNamobi sein Komplement wird noch im UNISYS 2200-System stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv

2
Ich habe mich noch nie mit den Anforderungen an die Ergänzung befasst - garantiert der Standard dies tatsächlich 0und -0ist anders ? Ich hätte ehrlich gesagt erwartet, dass es sich eher so verhält, als würde es zwei Bit-Darstellungen mit demselben Wert zulassen, und Ihr Programm kann jedes verwenden, nach dem es sich anfühlt.

8
@ Hurkly: Nein, selbst wenn eine negative Nulldarstellung vorhanden ist, garantiert der Standard nicht, dass die Zuweisung oder Initialisierung unter Verwendung des Ausdrucks -0, dh das Ergebnis der Anwendung des unären -Operators auf die Ganzzahlkonstante 0, eine negative Nulldarstellung ist. Unabhängig von der Darstellung sagt der Standard niemals 0und -0sind mathematisch unterschiedliche Werte, nur dass es möglicherweise ein negatives Null-Bitmuster gibt. Wenn ja, stellt es immer noch den gleichen numerischen Wert dar, 0.
Steve Jessop

14

Für eine int(in der fast universellen "2er-Komplement" -Darstellung) sind die Darstellungen von 0und -0gleich. (Sie können für andere Zahlendarstellungen unterschiedlich sein, z. B. Gleitkomma nach IEEE 754.)


9
>> Angenommen, eine 2er-Komplement-Darstellung
Marco A.

12

Beginnen wir mit der Darstellung von 0 im 2er-Komplement (natürlich gibt es viele andere Systeme und Darstellungen, hier beziehe ich mich auf diese spezifische), vorausgesetzt 8-Bit, Null ist:

0000 0000

Lassen Sie uns nun alle Bits umdrehen und 1 addieren, um das 2er-Komplement zu erhalten:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

wir haben 0000 0000, und das ist auch die Darstellung von -0.

Beachten Sie jedoch, dass im Komplement von 1 die vorzeichenbehaftete 0 0000 0000 ist, -0 jedoch 1111 1111.


1
Kann ich bitte wissen, warum die Abstimmungen, um meine Antwort zu verbessern?
Maroun

1
Während die meisten anderen Antworten technisch korrekt sind, ist Ihre Antwort praktisch und bietet eine Implementierung. Gut.
Umlcat

9

Ich habe mich entschlossen, diese Antwort offen zu lassen, da C- und C ++ - Implementierungen normalerweise eng miteinander verbunden sind, aber tatsächlich nicht dem C-Standard entspricht, wie ich dachte. Der Punkt bleibt, dass der C ++ - Standard nicht spezifiziert, was in solchen Fällen passiert. Es ist auch wichtig, dass Nicht-Zweier-Komplement-Darstellungen in der realen Welt äußerst selten sind und dass sie, selbst wenn sie existieren, den Unterschied in vielen Fällen oft verbergen, anstatt ihn als etwas zu entlarven, das jemand leicht erwarten könnte, zu entdecken.


Das Verhalten negativer Nullen in den Ganzzahldarstellungen, in denen sie existieren, ist im C ++ - Standard nicht so streng definiert wie im C-Standard. Es wird jedoch die C-Norm (ISO / IEC 9899: 1999) als normative Referenz auf höchster Ebene angeführt [1.2].

Im C-Standard [6.2.6.2] kann eine negative Null nur das Ergebnis von bitweisen Operationen oder Operationen sein, bei denen bereits eine negative Null vorhanden ist (z. B. Multiplizieren oder Teilen einer negativen Null mit einem Wert oder Hinzufügen einer negativen Null zu Null) - Wenn Sie den unären Minusoperator auf einen Wert einer normalen Null anwenden, wie in Ihrem Beispiel, wird daher garantiert eine normale Null erhalten.

Selbst in den Fällen, in denen eine negative Null erzeugt werden kann , gibt es keine Garantie dafür, selbst auf einem System, das eine negative Null unterstützt:

Es ist nicht spezifiziert, ob diese Fälle tatsächlich eine negative Null oder eine normale Null erzeugen und ob eine negative Null eine normale Null wird, wenn sie in einem Objekt gespeichert wird.

Daher können wir schließen: Nein, es gibt keinen zuverlässigen Weg, um diesen Fall zu erkennen. Auch wenn nicht die Tatsache, dass Darstellungen ohne Zweierkomplement in modernen Computersystemen sehr ungewöhnlich sind.

Der C ++ - Standard erwähnt seinerseits den Begriff "negative Null" nicht und diskutiert die Details der vorzeichenbehafteten Größe und der eigenen Komplementdarstellungen nur sehr wenig, mit Ausnahme der Anmerkung [3.9.1 Abs. 7], dass sie zulässig sind.


Im Allgemeinen bedeutet die Tatsache, dass etwas in C wahr / erforderlich ist, nicht unbedingt, dass es in C ++ wahr / erforderlich ist. Die Tatsache, dass C eine normative Referenz ist, bedeutet, dass C ++ für verschiedene Dinge (hauptsächlich den Inhalt von Standardheadern) auf den C-Standard verweist, aber die Definition von Ganzzahltypen gehört nicht dazu. Das Fehlen einer garantierten Methode zur Erzeugung einer negativen Null bedeutet jedoch, dass das, was Sie schließen, immer noch wahr ist. Es gibt keine sichere Möglichkeit, eine mit Arithmetik zu generieren, selbst wenn die Darstellung vorhanden ist.
Steve Jessop

Warum geht der C ++ - Standard dann so viel weniger ins Detail?
Random832

1
Persönlicher Geschmack, denke ich, wenn die Anzahl der Personen, die über den C ++ - Standard abstimmen, als "persönlich" angesehen werden kann :-) Wenn er sich jedoch für die Definitionen dem C-Standard widersetzen würde, könnte er einen ordnungsgemäßen Job machen und enthalten kein Detail, wie es in einigen anderen Fällen der Fall ist.
Steve Jessop

"C ++ ist eine Allzweck-Programmiersprache, die auf der Programmiersprache C basiert, wie in ISO / IEC 9899: 1999 Programmiersprachen - C (im Folgenden als C-Standard bezeichnet) beschrieben." [1.1 Abs. 2] eine normative Bedeutung haben? Ich dachte, dass dies generell den C-Standard für alles beinhalten sollte, was nicht speziell vom C ++ - Standard überschrieben wird.
Random832

@ Random832 Nr nur eine historische Note ist es (es gibt zum Beispiel keine _Booloder _Complexoder bezeichnet initializers oder Verbindung Literale in C ++). Der C ++ - Standard weiß, wie man den C-Standard einbindet, wenn er möchte - z. B. [basic.fundamental] / p3: "Die vorzeichenbehafteten und vorzeichenlosen Ganzzahltypen müssen die im C-Standard, Abschnitt 5.2.4.2.1, angegebenen Einschränkungen erfüllen."
TC

8

Wenn Ihre Maschine unterschiedliche Darstellungen für -0und hat +0, memcmpkönnen Sie diese unterscheiden.

Wenn Füllbits vorhanden sind, kann es tatsächlich auch mehrere Darstellungen für andere Werte als Null geben.


5

In der C ++ - Sprachspezifikation gibt es keine negative Null .

Die einzige Bedeutung, die diese beiden Wörter haben, ist der unäre Operator, auf den -angewendet wird 0, ebenso wie drei plus fünf nur der binäre Operator ist +, der auf 3und angewendet wird 5.

Wenn es eine eindeutige negative Null gäbe, wäre das Zweierkomplement (die häufigste Darstellung von Ganzzahltypen) eine unzureichende Darstellung für C ++ - Implementierungen, da es keine Möglichkeit gibt, zwei Formen von Null darzustellen.


Im Gegensatz dazu haben Gleitkommawerte (nach IEEE) getrennte positive und negative Nullen. Sie können beispielsweise unterschieden werden, wenn 1 durch sie geteilt wird. Positive Null erzeugt positive Unendlichkeit; Eine negative Null erzeugt eine negative Unendlichkeit.


Wenn es jedoch unterschiedliche Speicherdarstellungen von int 0 (oder einem int oder einem anderen Wert eines anderen Typs) gibt, können Sie Folgendes memcmpfeststellen:

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}

In diesem Fall würden die beiden Werte außerhalb der direkten Speicheroperationen natürlich immer noch genauso funktionieren.


3
Tatsächlich bedeutet die Sprache, die ihre Existenz nicht vorschreibt, nicht, dass sie ihre Abwesenheit vorschreibt. Hinweis: Es gibt keine Mandate.
Deduplikator

2
@Deduplicator, irgendwie. Mit "in der Sprache C ++", ich meine, "in der Sprache C ++ Spezifikation ". Da in der Spezifikation auch keine Froobinatoren erwähnt werden, könnte ich sagen, dass "C ++ keine Froobinatoren hat", ohne zu viel Mehrdeutigkeit. Ich dachte das wäre klar, aber ich werde es verbessern.
Paul Draper

1
In der Sprachspezifikation werden auch keine Einhörner erwähnt.
Ypercubeᵀᴹ

2

Zur Vereinfachung fand ich es einfacher zu visualisieren.

Der Typ int (_32) wird mit 32 Bit gespeichert . 32 Bit bedeutet 2 ^ 32 = 4294967296 eindeutige Werte . Also:

Der vorzeichenlose int- Datenbereich liegt zwischen 0 und 4.294.967.295

Bei negativen Werten hängt es davon ab, wie sie gespeichert werden. Im Fall

Im Falle des One-Komplements existiert der Wert -0.


2
Ich habe nicht herabgestimmt, aber die Plattformen, für die intnicht in 32 Bit gespeichert ist, sind heutzutage beliebter als Plattformen mit eigener Ergänzung.
Maciej Piechotka
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.