È possibile distinguere tra 0 e -0?


94

So che i valori interi 0e -0sono essenzialmente gli stessi. Ma mi chiedo se sia possibile distinguerli.

Ad esempio, come faccio a sapere se è stata assegnata una variabile -0?

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

int num = -0;
int additinon = 5;

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

Il valore -0salvato in memoria è esattamente lo stesso di 0?


9
Per i numeri interi, non c'è differenza.
Maroun

14
Questo dipende dall'implementazione, ma per le implementazioni in cui intè rappresentato nel complemento di 2 (di gran lunga il più comunemente riscontrato) 0e -0hanno rappresentazioni bit per bit identiche.
Mankarse

11
Su una macchina a complemento a 2 non c'è differenza a livello di bit.
Marco A.

17
@VirtualSnake: cosa significa "in binario"? Ci sono, infatti, codifiche binarie per le quali non v'è una distinzione tra -0 e 0. Segno e grandezza, per esempio.
Benjamin Lindley

8
@VirtualSnake Esatto, stiamo parlando int. Vedere la codifica del complemento di uno .
CiaPan

Risposte:


112

Dipende dalla macchina che stai prendendo di mira.

Su una macchina che utilizza una rappresentazione in complemento a 2 per interi non c'è differenza a livello di bit tra 0e -0(hanno la stessa rappresentazione)

Se la tua macchina usasse un complemento , potresti sicuramente farlo

0000 0000   -> signed0
1111 1111   -> signed   0

Ovviamente stiamo parlando dell'utilizzo del supporto nativo , i processori della serie x86 hanno il supporto nativo per la rappresentazione in complemento a due dei numeri con segno. L'uso di altre rappresentazioni è sicuramente possibile, ma probabilmente sarebbe meno efficiente e richiederebbe più istruzioni.

(Come ha anche notato JerryCoffin: anche se il proprio complemento è stato considerato principalmente per ragioni storiche, le rappresentazioni di magnitudo con segno sono ancora abbastanza comuni e hanno una rappresentazione separata per lo zero negativo e positivo)


6
@TobiMcNamobi: Probabilmente non abbastanza da preoccuparsene. Sarei sorpreso se qualcuno si fosse mai preso la briga di portare un compilatore C ++ per produrre output per una macchina del genere.
Benjamin Lindley

1
Sono d'accordo con Benjamin, storicamente ci sono state macchine che lo usano, ma al giorno d'oggi non mi capita di conoscere macchine di produzione che lo usano. Tuttavia è sempre bene sapere e tenere a mente.
Marco A.

4
Di @TobiMcNamobi complemento a uno è ancora in uso nel 2200 UNISYS sistema stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv

2
Non ho mai esaminato i requisiti del complemento uno - lo standard lo garantisce effettivamente 0e -0sono diversi ? Onestamente mi sarei aspettato che si comportasse più come se consentisse rappresentazioni a due bit dello stesso valore, e il tuo programma può usare quello che preferisce.

8
@Hurkly: no, anche se esiste una rappresentazione di zero negativo, lo standard non garantisce che l'assegnazione o l'inizializzazione utilizzando l'espressione -0, cioè il risultato dell'applicazione -dell'operatore unario alla costante intera 0, sia una rappresentazione di zero negativo. Indipendentemente dalla rappresentazione, lo standard non dice mai 0e -0sono valori matematicamente diversi, solo che potrebbe esserci uno schema di bit zero negativo. Se c'è, rappresenta ancora lo stesso valore numerico, 0.
Steve Jessop

14

Per una int(nella quasi universale rappresentazione "complemento a 2") le rappresentazioni di 0e -0sono le stesse. (Possono essere diversi per altre rappresentazioni numeriche, ad es. IEEE 754 virgola mobile.)


9
>> Ipotizzando una rappresentazione in complemento di 2
Marco A.

12

Cominciamo con la rappresentazione di 0 nel complemento di 2 (ovviamente esistono molti altri sistemi e rappresentazioni, qui mi riferisco a questo specifico), assumendo che 8 bit, zero sia:

0000 0000

Ora capovolgiamo tutti i bit e aggiungiamo 1 per ottenere il complemento di 2:

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

abbiamo 0000 0000, e questa è anche la rappresentazione di -0.

Ma nota che nel complemento di 1, firmato 0 è 0000 0000, ma -0 è 1111 1111.


1
Posso sapere perché i voti negativi per migliorare la mia risposta per favore?
Maroun

1
Sebbene la maggior parte delle altre risposte siano tecnicamente corrette, la tua risposta è pratica e fornisce un'implementazione. Buona.
umlcat

9

Ho deciso di lasciare questa risposta poiché le implementazioni C e C ++ sono solitamente strettamente correlate, ma in realtà non si rimanda allo standard C come pensavo. Resta il punto che lo standard C ++ non specifica cosa succede per casi come questi. È anche importante che le rappresentazioni senza complemento a due siano estremamente rare nel mondo reale e che anche dove esistono spesso nascondono la differenza in molti casi piuttosto che esporla come qualcosa che qualcuno potrebbe facilmente aspettarsi di scoprire.


Il comportamento degli zeri negativi nelle rappresentazioni di interi in cui esistono non è così rigorosamente definito nello standard C ++ come nello standard C. Tuttavia, cita lo standard C (ISO / IEC 9899: 1999) come riferimento normativo al livello più alto [1.2].

Nello standard C [6.2.6.2], uno zero negativo può essere solo il risultato di operazioni bit per bit, o operazioni in cui è già presente uno zero negativo (ad esempio, moltiplicando o dividendo lo zero negativo per un valore, o aggiungendo uno zero negativo a zero) - l'applicazione dell'operatore meno unario a un valore di uno zero normale, come nel tuo esempio, è quindi garantito che risulti in uno zero normale.

Anche nei casi che possono generare uno zero negativo, non vi è alcuna garanzia che lo faranno, anche su un sistema che supporta lo zero negativo:

Non è specificato se questi casi generano effettivamente uno zero negativo o uno zero normale e se uno zero negativo diventa uno zero normale quando viene memorizzato in un oggetto.

Pertanto, possiamo concludere: no, non esiste un modo affidabile per rilevare questo caso. Anche se non per il fatto che le rappresentazioni senza complemento a due sono molto rare nei moderni sistemi informatici.

Lo standard C ++, da parte sua, non fa menzione del termine "zero negativo", e ha pochissime discussioni sui dettagli della grandezza con segno e sulle rappresentazioni del complemento a uno, tranne per notare [3.9.1 paragrafo 7] che sono consentiti.


In generale no, il fatto che qualcosa sia vero / richiesto in C non significa necessariamente che sia vero / richiesto in C ++. Il fatto che C sia un riferimento normativo significa che C ++ si riferisce allo standard C per varie cose (principalmente il contenuto delle intestazioni standard), ma la definizione di tipi interi non è una di quelle cose. Tuttavia, l'assenza di un modo garantito per produrre uno zero negativo significa che ciò che si conclude è ancora vero, non esiste un modo sicuro per generarne uno usando l'aritmetica anche se la rappresentazione esiste.
Steve Jessop

Allora perché lo standard C ++ va in così meno dettagli su cose come questa?
Casuale 832

1
Gusto personale, penso, se il numero di persone che votano per lo standard C ++ può essere considerato "personale" :-) Se dovesse rimandare allo standard C per le definizioni, però, allora potrebbe fare un buon lavoro e non contengono dettagli, come in altri casi.
Steve Jessop

"Il C ++ è un linguaggio di programmazione generico basato sul linguaggio di programmazione C come descritto in ISO / IEC 9899: 1999 Linguaggi di programmazione - C (di seguito denominato standard C)." [1.1 paragrafo 2] hanno un significato normativo? Ho pensato che fosse destinato a incorporare generalmente lo standard C per tutto ciò che non è specificamente sovrascritto dallo standard C ++.
Casuale 832

@ Solo una nota storico di Random832 No. (c'è, per esempio, nessuno _Boolo _Complexo inizializzatori designati o letterali composti in C ++). Lo standard C ++ sa come incorporare lo standard C quando lo desidera, ad esempio [basic.fundamental] / p3: "I tipi interi con segno e senza segno devono soddisfare i vincoli dati nello standard C, sezione 5.2.4.2.1."
TC

8

Se la tua macchina ha rappresentazioni distinte per -0e +0, memcmpsarà in grado di distinguerle.

Se sono presenti bit di riempimento, potrebbero esserci anche più rappresentazioni per valori diversi da zero.


5

Nella specifica del linguaggio C ++, non esiste un int come zero negativo .

L'unico significato che queste due parole hanno è l'operatore unario -applicato a 0, proprio come tre più cinque è solo l'operatore binario +applicato a 3e 5.

Se ci fosse uno zero negativo distinto , il complemento a due (la rappresentazione più comune dei tipi interi) sarebbe una rappresentazione insufficiente per le implementazioni C ++, poiché non c'è modo di rappresentare due forme di zero.


Al contrario, i punti mobili (che seguono IEEE) hanno zeri positivi e negativi separati. Possono essere distinti, ad esempio, quando si divide 1 da loro. Lo zero positivo produce un infinito positivo; lo zero negativo produce un infinito negativo.


Tuttavia, se ci sono diverse rappresentazioni di memoria di int 0 (o qualsiasi int o qualsiasi altro valore di qualsiasi altro tipo), puoi usare memcmpper scoprire che:

#include <string>

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

Naturalmente, se ciò accadesse, al di fuori delle operazioni di memoria diretta, i due valori funzionerebbero ancora esattamente allo stesso modo.


3
In realtà, la lingua che non impone la sua esistenza non significa che ne imponga l'assenza. Suggerimento: non richiede nessuno dei due.
Deduplicatore

2
@Deduplicator, una specie di. Con "nel linguaggio C ++", intendo "nella specifica del linguaggio C ++ ". Dal momento che non vi è alcuna menzione di froobinator nelle specifiche, potrei dire "C ++ non ha froobinator" senza troppe ambiguità. Pensavo fosse chiaro, ma lo migliorerò.
Paul Draper

1
Le specifiche della lingua non menzionano nemmeno gli unicorni.
ypercubeᵀᴹ

2

Per semplificare ho trovato più facile visualizzare.

Il tipo int (_32) viene memorizzato con 32 bit . 32 bit significa 2 ^ 32 = 4294967296 valori univoci . Quindi:

l'intervallo di dati int senza segno è compreso tra 0 e 4.294.967.295

In caso di valori negativi dipende da come vengono memorizzati. Nel caso

Nel caso del complemento a uno esiste il valore -0.


2
Non ho downvoting, ma le piattaforme per le quali intnon è memorizzato a 32 bit sono più popolari delle piattaforme con il proprio complemento al giorno d'oggi.
Maciej Piechotka
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.