Verhalten der negativen Null auf einer eigenen Komplement-Architektur?

9

Betrachten Sie den folgenden Code für eine eigene Komplement-Architektur:

%Vor%
  • Welche Ausgabe würde der Code erzeugen?
  • Welche Zeilen sind vom Standard definiert, welche Zeilen sind implementierungsabhängig und welche Zeilen sind nicht definiert?
Vincent 08.12.2015, 05:57
quelle

3 Antworten

3

Basierend auf meiner Interpretation des Standards:

Der C ++ - Standard in §3.9.1 / p3 Grundtypen [basic.fundamental] wirft den Ball tatsächlich in den C-Standard:

  

Die Ganzzahlarten mit und ohne Vorzeichen müssen die Bedingungen erfüllen   in der C-Norm, Abschnitt 5.2.4.2.1 gegeben.

Wenn wir jetzt zu ISO / IEC 9899: 2011 Abschnitt 5.2.4.2.1 gehen, gibt es als eine Vorwärtsreferenz auf §6.2.6.2 / p2 Ganzzahlige Typen ( Betonung meiner ) stark>):

  

Wenn das Vorzeichenbit Null ist, hat dies keinen Einfluss auf den resultierenden Wert. Ob   das Vorzeichenbit ist eins, der Wert soll in einem der geändert werden   folgende Möglichkeiten:

     
  • wird der entsprechende Wert mit Vorzeichenbit 0 negiert (Vorzeichen und   Größe);

  •   
  • Das Vorzeichenbit hat den Wert - (2 ^ M) (Zweierkomplement);

  •   
  • Das Vorzeichenbit hat den Wert - (2 ^ M - 1) (Einerkomplement).

  •   

Welche davon gilt, ist implementierungsdefiniert , ob der Wert mit Vorzeichenbit 1 und alle Wertbits Null sind (für die ersten beiden),   oder mit Vorzeichenbit und allen Wertbits 1 (für Einerkomplement), ist a   Trap-Repräsentation oder ein normaler Wert. Im Falle von Zeichen und   Größe und Einser ergänzen, wenn diese Repräsentation normal ist   Wert wird eine negative Null genannt.

Folglich ist die Existenz einer negativen Null als Implementierung definiert.

Wenn wir in Absatz 3 weitermachen:

  

Wenn die Implementierung negative Nullen unterstützt, sollten sie erzeugt werden   nur durch:

     
  • die & amp;, |, ^, ~, & lt; & lt; und & gt; & gt; Operatoren mit Operanden, die solche erzeugen   ein Wert;

  •   
  • Die Operatoren +, -, *, / und%, bei denen ein Operand eine negative Null ist   und das Ergebnis ist Null;

  •   
  • zusammengesetzte Zuweisungsoperatoren basierend auf den oben genannten Fällen.

  •   

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

Folglich ist es nicht spezifiziert, ob die verwandten Fälle, die Sie angezeigt haben, überhaupt eine negative Null erzeugen werden.

Gehen Sie nun in Absatz 4 vor:

  

Wenn die Implementierung keine negativen Nullen unterstützt, wird das Verhalten von   die & amp;, |, ^, ~, & lt; & lt; und & gt; & gt; Operatoren mit Operanden, die erzeugen würden   Ein solcher Wert ist nicht definiert.

Ob die zugehörigen Operationen zu undefiniertem Verhalten führen, hängt daher davon ab, ob die Implementierung negative Nullen unterstützt.

    
101010 08.12.2015, 08:18
quelle
3

Zunächst einmal ist deine erste Prämisse falsch:

%Vor%

sollte für jede konforme Architektur eine normale Null ergeben.

Referenzen dazu wurden in @ 101010's Antwort gegeben:

3.9.1 Grundtypen [grundlegend.fundamental] §3:

  

... Die vorzeichenbehaftete und vorzeichenlose Ganzzahl   Die Typen müssen die in der C-Norm Abschnitt 5.2.4.2.1 angegebenen Einschränkungen erfüllen.

Später in C Referenz: 5.2.4.2.1 Größen von Integer-Typen

  

... Vorwärtsreferenzen: Darstellungen von Typen (6.2.6)

und (immer noch C): 6.2.6 Darstellungen von Typen / 6.2.6.2 Ganzzahlige Typen § 3

  

Wenn die Implementierung negative Nullen unterstützt, sollten sie nur erzeugt werden durch:

     
  • die & amp;, |, ^, ~, & lt; & lt; und & gt; & gt; Operatoren mit Argumenten, die einen solchen Wert erzeugen;

  •   
  • Die Operatoren +, -, *, / und%, bei denen ein Argument eine negative Null ist und das Ergebnis ist   Null;

  •   
  • zusammengesetzte Zuweisungsoperatoren basierend auf den oben genannten Fällen.

  •   

So negzero = -0 ist nicht ein solches Konstrukt und soll nicht eine negative 0 ergeben.

Für die folgenden Zeilen gehe ich davon aus, dass das negative 0 bitweise auf einer Implementierung erzeugt wurde, die es unterstützt .

C ++ - Standard spricht überhaupt nicht von negativen Nullen, und C-Standard sagt nur von ihnen, dass ihre Existenz implementierungsabhängig ist. Ich konnte keinen Absatz explizit finden, der besagt, ob eine negative Null für einen relationalen oder Gleichheitsoperator gleich einer normalen Null sein sollte.

Also werde ich nur in C verweisen: 6.5.8 Relationale Operatoren §6

  

Jeder der Operatoren & lt; (weniger als), & gt; (größer als), & lt; = (kleiner oder gleich) und & gt; =   (größer oder gleich) soll 1 ergeben, wenn die angegebene Relation wahr ist, und 0, wenn sie falsch ist.92)   Das Ergebnis hat den Typ int.

und in C ++ 5.9 Relationale Operatoren [expr.rel] §5

  

Wenn beide Operanden (nach Konvertierungen) Arithmetik- oder Aufzählungstyp sind, muss jeder der Operatoren ergeben   Wahr, wenn die angegebene Beziehung wahr und falsch ist, wenn sie falsch ist.

Meine Interpretation von Standard ist, dass eine Implementierung eine alternative Darstellung des ganzzahligen Wertes 0 ( negativer Null ) erlauben kann, aber es ist immer noch eine Repräsentation des Wertes 0 und sollte dementsprechend in jeder Arithmetik funktionieren Ausdruck, weil C 6.2.6.2 Ganzzahlige Typen § 3 sagt:

  

negative Nullen [...] werden nur erzeugt durch [...] die Operatoren +, -, *, / und%, wobei ein Argument eine negative Null ist und das Ergebnis ist   null

Das heißt, wenn das Ergebnis nicht 0 ist, sollte eine negative 0 als normale Null funktionieren.

Diese beiden Zeilen sind also perfekt definiert und sollten 1 :

ergeben %Vor%

Diese Zeile ist eindeutig als implementierungsabhängig definiert:

%Vor%

, weil eine Implementierung Padding-Bits haben könnte. Wenn keine Padding-Bits vorhanden sind, ist ~zero negzero , so dass ~negzero ein 0 erzeugen sollte, aber ich konnte im Standard nicht finden, wenn eine negative Null angezeigt werden soll als 0 oder als -0 . Ein negativer Fließkomma 0 sollte mit einem Minuszeichen angezeigt werden, aber nichts scheint für einen ganzen negativen Wert explizit zu sein.

Für die letzten 3 Zeilen, die relationale und equity-Operatoren enthalten, gibt es im Standard keine explizite Definition, daher würde ich sagen, dass die Implementierung definiert ist

TL / DR:

Implementierungsabhängig:

%Vor%

Perfekt definiert und sollte 1:

erzeugen %Vor%     
Serge Ballesta 08.12.2015 10:18
quelle
-2

Zuallererst sind die Einser-Komplement-Architekturen (oder sogar die negative Null) ziemlich selten, und dafür gibt es einen Grund. Es ist grundsätzlich einfacher, (hardwaremäßig) Zweierkomplement als das Einerkomplement hinzuzufügen.

Der Code, den Sie gepostet haben, scheint kein undefiniertes Verhalten oder sogar implementiertes Verhalten zu haben, er sollte wahrscheinlich nicht zu einer negativen Null führen (oder er sollte nicht von der normalen Null unterschieden werden).

Negative Nullen sollten nicht so einfach zu erzeugen sein (und wenn Sie das schaffen, ist es das im besten Fall implementierte Verhalten). Wenn es sich um eine Einerkomplement-Architektur handelt, werden sie von ~0 (bitweise Inversion) anstatt -0 erzeugt.

Der C ++ - Standard ist ziemlich vage über die tatsächliche Darstellung und Anforderungen an das Verhalten von Grundtypen (was bedeutet, dass die Spezifikation nur die tatsächliche Bedeutung der Zahl behandelt). Das bedeutet, dass Sie im Grunde genommen kein Glück darin haben, die interne Repräsentation der Zahl und ihren tatsächlichen Wert in Beziehung zu setzen. Selbst wenn Sie das richtig gemacht haben und ~0 verwendet haben (oder wie auch immer die Implementierung aussehen mag), scheint sich der Standard immer noch nicht mit der Darstellung zu befassen, da der Wert der negativen Null immer noch Null ist.

%Vor%

Die drei ersten Zeilen sollten die gleiche Ausgabe erzeugen, als ob negzero genauso definiert wäre wie zero . Die dritte Zeile sollte zwei Nullen ausgeben (da der Standard erfordert, dass 0 als 0 ohne Vorzeichen gerendert wird). Die zwei letzten sollten eine ausgeben.

Es gibt einige Hinweise (zur Erzeugung negativer Nullen), die im C-Standard zu finden sind, der die negative Null angibt, aber ich denke nicht, dass es irgendwelche Erwähnungen darüber gibt, dass sie weniger vergleichen sollten als normale Null. Der C-Standard schlägt vor, dass die negative Null den Speicher im Objekt nicht überleben könnte (deshalb habe ich das im obigen Beispiel vermieden).

Wie C und C ++ zusammenhängen, ist es vernünftig zu denken, dass in C ++ eine negative Null auf dieselbe Weise erzeugt wird wie in C, und der Standard scheint das zuzulassen. Während der C ++ - Standard andere Möglichkeiten bietet (über undefiniertes Verhalten), scheint jedoch kein anderes über definiertes Verhalten verfügbar zu sein. Es ist also ziemlich sicher, dass, wenn eine C ++ - Implementierung in der Lage sein soll, negative Nullen in einer vernünftigen Weise zu erzeugen, dieselbe wäre wie für eine ähnliche C-Implementierung.

    
skyking 08.12.2015 07:26
quelle