Czy można rozróżnić między 0 a -0?


94

Wiem, że wartości całkowite 0i -0są zasadniczo takie same. Zastanawiam się jednak, czy można je rozróżnić.

Na przykład, skąd mam wiedzieć, czy zmienna została przypisana -0?

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

int num = -0;
int additinon = 5;

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

Czy wartość -0zapisana w pamięci jest dokładnie taka sama jak 0?


9
W przypadku liczb całkowitych nie ma różnicy.
Maroun

14
Zależy to od implementacji, ale w przypadku implementacji, w których intjest reprezentowany w uzupełnieniu 2 (zdecydowanie najczęściej spotykanym) 0i -0ma identyczne reprezentacje bitowe.
Mankarse

11
Na maszynie z dopełnieniem 2 nie ma różnicy na poziomie bitów.
Marco A.

17
@VirtualSnake: Co oznacza „binarnie”? Są to w rzeczywistości, kodowanie binarne, dla których nie ma rozróżnienia między -0 i 0. znak i wielkości, na przykład.
Benjamin Lindley

8
@VirtualSnake Zgadza się, mówimy o int. Zobacz kodowanie dopełniające Ones .
CiaPan

Odpowiedzi:


112

To zależy od maszyny, na którą celujesz.

Na komputerze używającym reprezentacji dopełnienia do 2 dla liczb całkowitych nie ma różnicy na poziomie bitów między 0a -0(mają tę samą reprezentację)

Gdyby twoja maszyna korzystała z dopełniacza , zdecydowanie możesz

0000 0000   -> signed01111 1111   -> signed0

Oczywiście mówimy o używaniu natywnej obsługi , procesory z serii x86 mają natywną obsługę uzupełniającej reprezentacji podpisanych liczb. Korzystanie z innych reprezentacji jest zdecydowanie możliwe, ale prawdopodobnie byłoby mniej wydajne i wymagałoby więcej instrukcji.

(Jak zauważył również JerryCoffin: nawet jeśli czyjeś uzupełnienie było rozważane głównie z powodów historycznych, reprezentacje wielkości ze znakiem są nadal dość powszechne i mają oddzielną reprezentację dla zera ujemnego i dodatniego)


6
@TobiMcNamobi: Mało prawdopodobne, by kiedykolwiek się o to martwić. Zdziwiłbym się, gdyby ktoś kiedykolwiek zadał sobie trud przeniesienia kompilatora C ++ w celu wygenerowania danych wyjściowych dla takiej maszyny.
Benjamin Lindley

1
Zgadzam się z Benjaminem, w przeszłości były używane maszyny, ale obecnie nie znam maszyn produkcyjnych, które go używają. Niemniej jednak zawsze dobrze jest wiedzieć i o tym pamiętać.
Marco A.

4
Uzupełnienie @TobiMcNamobi jest nadal w użyciu w systemie UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv

2
Nigdy nie patrzyłem na wymagania dotyczące komplementów - czy norma faktycznie to gwarantuje 0i czy -0inne ? Szczerze mówiąc, spodziewałbym się, że będzie zachowywał się bardziej jak zezwalanie na dwie bitowe reprezentacje tej samej wartości, a twój program może używać tego, na co się wydaje.

8
@Hurkly: nie, nawet jeśli istnieje ujemna reprezentacja zera, standard nie gwarantuje, że przypisanie lub inicjalizacja za pomocą wyrażenia -0, to znaczy wynik zastosowania -operatora jednoargumentowego do stałej liczby całkowitej 0, jest reprezentacją ujemnego zera. Niezależnie od reprezentacji, standard nigdy nie mówi 0i -0są matematycznie różnymi wartościami, tylko że może istnieć wzór bitowy ujemny-zero. Jeśli tak, nadal reprezentuje tę samą wartość liczbową, 0.
Steve Jessop

14

Dla int(w prawie uniwersalnej reprezentacji „dopełnienia do 2”) reprezentacje 0i -0są takie same. (Mogą być różne dla innych reprezentacji liczb, np. Zmiennoprzecinkowe IEEE 754).


9
>> Zakładając, że dopełnienie do 2
Marco A.

12

Zacznijmy od przedstawienia 0 w uzupełnieniu do 2 (oczywiście istnieje wiele innych systemów i reprezentacji, tutaj odnoszę się do tego konkretnego), przy założeniu, że 8-bitowe zero to:

0000 0000

Teraz odwróćmy wszystkie bity i dodajmy 1, aby uzyskać dopełnienie do 2:

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

mamy 0000 0000, i to jest również reprezentacja -0.

Ale pamiętaj, że w uzupełnieniu 1 ze znakiem 0 to 0000 0000, ale -0 to 1111 1111.


1
Czy mogę wiedzieć, dlaczego głosy przeciwne, aby poprawić moją odpowiedź, proszę?
Maroun

1
Chociaż większość pozostałych odpowiedzi jest poprawna technicznie, Twoja odpowiedź jest praktyczna i zapewnia implementację. Dobry.
umlcat

9

Postanowiłem pozostawić tę odpowiedź, ponieważ implementacje C i C ++ są zwykle ściśle powiązane, ale w rzeczywistości nie odstają od standardu C, jak myślałem. Chodzi o to, że standard C ++ nie określa, co się dzieje w takich przypadkach. Istotne jest również to, że reprezentacje dopełniające inne niż dwójki są niezwykle rzadkie w prawdziwym świecie, a nawet tam, gdzie istnieją, często ukrywają różnicę w wielu przypadkach, zamiast ujawniać ją jako coś, czego ktoś mógłby z łatwością oczekiwać.


Zachowanie zer ujemnych w reprezentacjach liczb całkowitych, w których istnieją, nie jest tak rygorystycznie zdefiniowane w standardzie C ++, jak w standardzie C. Cytuje jednak normę C (ISO / IEC 9899: 1999) jako odniesienie normatywne na najwyższym poziomie [1.2].

W standardzie C [6.2.6.2] ujemne zero może być wynikiem tylko operacji bitowych lub operacji, w których ujemne zero jest już obecne (na przykład mnożenie lub dzielenie ujemnego zera przez wartość lub dodanie ujemnego zera do zero) - zastosowanie jednoargumentowego operatora minus do wartości normalnego zera, tak jak w twoim przykładzie, gwarantuje zatem normalne zero.

Nawet w przypadkach, które mogą wygenerować ujemne zero, nie ma gwarancji, że tak się stanie, nawet w systemie, który obsługuje ujemne zero:

Nie jest określone, czy te przypadki faktycznie generują ujemne zero, czy normalne zero i czy ujemne zero staje się normalnym zerem, gdy jest przechowywane w obiekcie.

Dlatego możemy stwierdzić: nie, nie ma niezawodnego sposobu na wykrycie tego przypadku.Nawet gdyby nie fakt, że reprezentacje z dopełnieniem innym niż dwójki są bardzo rzadkie w nowoczesnych systemach komputerowych.

Standard C ++ ze swojej strony nie wspomina o terminie „ujemne zero” i zawiera bardzo mało dyskusji na temat szczegółów wielkości ze znakiem i reprezentacji dopełnień, z wyjątkiem uwagi [3.9.1 akapit 7], że są one dozwolone.


Generalnie nie, fakt, że coś jest prawdziwe / wymagane w C , niekoniecznie oznacza, że ​​jest prawdą / wymagane w C ++. Fakt, że C jest odniesieniem normatywnym, oznacza, że ​​C ++ odwołuje się do standardu C dla różnych rzeczy (głównie zawartości standardowych nagłówków), ale definicja typów całkowitych nie jest jedną z tych rzeczy. Jednak brak gwarantowanego sposobu na wygenerowanie ujemnego zera oznacza, że ​​to, co wnioskujesz, jest nadal prawdziwe, nie ma pewnego sposobu na wygenerowanie go przy użyciu arytmetyki, nawet jeśli reprezentacja istnieje.
Steve Jessop

Dlaczego więc standard C ++ zawiera o wiele mniej szczegółów na takie tematy?
Random832

1
Myślę, że osobisty gust, jeśli liczbę osób głosujących na standard C ++ można uznać za „osobisty” :-) Jeśli jednak miałby odłożyć definicje do standardu C, to mógłby wykonać odpowiednią robotę i nie zawierają żadnych szczegółów, jak ma to miejsce w innych przypadkach.
Steve Jessop

Czy „C ++ jest językiem programowania ogólnego przeznaczenia opartym na języku programowania C, zgodnie z opisem w ISO / IEC 9899: 1999 Języki programowania - C (zwanym dalej standardem C)”. [1.1 para 2] ma jakiekolwiek znaczenie normatywne? Pomyślałem, że chodziło o włączenie standardu C do wszystkiego, co nie zostało specjalnie nadpisane przez standard C ++.
Random832

@ Tylko historycznej nocie Random832 Nie, to (nie, na przykład, nie _Boollub _Complexczy wyznaczone inicjalizatory lub związek literały w C ++). Standard C ++ wie, jak włączyć standard C, kiedy chce - np. [Basic.fundamental] / p3: "Typy liczb całkowitych ze znakiem i bez znaku powinny spełniać ograniczenia podane w standardzie C, sekcja 5.2.4.2.1."
TC

8

Jeśli twoja maszyna ma różne reprezentacje dla -0i +0, wtedy memcmpbędzie w stanie je rozróżnić.

Jeśli obecne są bity wypełniające, w rzeczywistości może istnieć wiele reprezentacji wartości innych niż zero.


5

W specyfikacji języka C ++ nie ma takiej liczby int, jak ujemne zero .

Jedyne znaczenie, jakie mają te dwa słowa, to operator jednoargumentowy -zastosowany do 0, tak jak trzy plus pięć to po prostu operator binarny +zastosowany do 3i 5.

Gdyby istniało wyraźne ujemne zero , uzupełnienie do dwóch (najczęstsza reprezentacja typów całkowitych) byłoby niewystarczającą reprezentacją dla implementacji C ++, ponieważ nie ma sposobu, aby przedstawić dwie formy zera.


W przeciwieństwie do tego zmiennoprzecinkowe (po IEEE) mają oddzielne zera dodatnie i ujemne. Można je rozróżnić np. Dzieląc przez siebie 1. Dodatnie zero daje dodatnią nieskończoność; ujemne zero daje ujemną nieskończoność.


Jeśli jednak zdarzy się, że istnieją różne reprezentacje pamięci int 0 (lub dowolnej wartości int lub dowolnej innej wartości dowolnego innego typu), możesz użyć, memcmpaby odkryć, że:

#include <string>

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

Oczywiście, gdyby tak się stało, poza bezpośrednimi operacjami pamięciowymi te dwie wartości nadal działałyby dokładnie w ten sam sposób.


3
W rzeczywistości język, który nie nakazuje jego istnienia, nie oznacza, że ​​nakazuje jego brak. Podpowiedź: nie upoważnia.
Deduplicator

2
@Deduplicator, w pewnym sensie. Przez „w języku C ++” mam na myśli „w specyfikacji języka C ++ ”. Ponieważ w specyfikacji nie ma również wzmianki o froobinatorach, mógłbym powiedzieć „C ++ nie ma froobinatorów” bez zbytniej wieloznaczności. Myślałem, że to jasne, ale poprawię to.
Paul Draper

1
Specyfikacja językowa nie wspomina również o jednorożcach.
ypercubeᵀᴹ

2

Aby uprościć, łatwiej było mi wizualizować.

Typ int (_32) jest przechowywany z 32 bitami . 32 bity oznaczają 2 ^ 32 = 4294967296 unikalnych wartości . Zatem:

Zakres danych bez znaku int wynosi od 0 do 4 294 967 295

W przypadku wartości ujemnych zależy to od sposobu ich przechowywania. W razie

W przypadku dopełnienia do jedynki istnieje wartość -0.


2
Nie przegłosowałem, ale platformy, dla których intnie są przechowywane w 32 bitach, są obecnie bardziej popularne niż platformy z własnym uzupełnieniem.
Maciej Piechotka
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.