Perché lo zero negativo è importante?


64

Sono confuso sul perché ci preoccupiamo di diverse rappresentazioni per zero positivo e negativo.

Ricordo vagamente la lettura di affermazioni secondo cui avere una rappresentazione zero negativa è estremamente importante nella programmazione che coinvolge numeri complessi. Non ho mai avuto l'opportunità di scrivere codice con numeri complessi, quindi sono un po 'confuso sul perché questo sarebbe il caso.

L'articolo di Wikipedia sul concetto non è particolarmente utile; fa solo vaghe affermazioni sullo zero con segno rendendo più semplici alcune operazioni matematiche in virgola mobile, se capisco correttamente. Questa risposta elenca un paio di funzioni che si comportano diversamente e forse si potrebbe dedurre dagli esempi se si ha familiarità con il modo in cui potrebbero essere utilizzate. (Anche se, l'esempio particolare delle complesse radici quadrate sembra completamente sbagliato, poiché i due numeri sono matematicamente equivalenti, a meno che non abbia un equivoco). Ma non sono stato in grado di trovare una chiara dichiarazione del tipo di problema che potresti incontrare se non ci fosse. Le maggiori risorse matematiche che sono riuscito a trovare affermano che non esiste alcuna distinzione tra i due da una prospettiva matematica e l'articolo di Wikipedia sembra suggerire che ciò sia visto raramente al di fuori dell'informatica oltre a descrivere i limiti.

Quindi, perché uno zero negativo è prezioso nell'informatica? Sono sicuro che mi sto perdendo qualcosa.


6
Lo zero negativo può segnalare underflow in un numero in virgola mobile IEEE, ma oltre a ciò, il suo utilizzo sembra essere controverso e oscuro. Se dovessi indovinare, direi che lo zero negativo è rappresentato in virgola mobile IEEE perché ... beh, puoi. Per un giro ancora più interessante, cercare le informazioni sulla segnalazione in virgola mobile NaN.
Robert Harvey,

1
Se l'esempio particolare è "1 / 0,0" / "1 / -0,0", 0 è un taglio di ramo per 1 / x e il limite dipende se ci si avvicina dal basso o dall'alto.
Vatine,

@Vatine No, l'esempio particolare è sqrt(-1+0i) = ie sqrt(-1-0i) = -i, sebbene vestito con una sintassi adeguata per alcuni linguaggi di programmazione, credo. Modificherò per essere più chiaro.
jpmc26,

3
Ho cercato programmatori , StackTranslate.it , Informatica , Matematica e Ingegneria . L'unica domanda che ho potuto trovare era Usi per valore a virgola mobile zero negativo? . Questa non può essere solo la seconda volta che si presenta!

Sono davvero sorpreso che nelle risposte non siano emersi numeri complessi, soprattutto dato l'esempio di radice quadrata che ho sottolineato.
jpmc26,

Risposte:


69

È necessario tenere presente che nell'aritmetica FPU, 0 non deve necessariamente significare esattamente zero, ma anche un valore troppo piccolo per essere rappresentato utilizzando un dato tipo di dati, ad es.

a = -1 / 1000000000000000000.0

a è troppo piccolo per essere rappresentato correttamente da float (32 bit), quindi è "arrotondato" a -0.

Ora, supponiamo che il nostro calcolo continui:

b = 1 / a

Poiché a è float, risulterà -infinito che è abbastanza lontano dalla risposta corretta di -100000000000000000000.0

Ora calcoliamo b se non c'è -0 (quindi a è arrotondato a +0):

b = 1 / +0
b = +infinity

Il risultato è di nuovo sbagliato a causa dell'arrotondamento, ma ora è "più sbagliato" - non solo numericamente, ma soprattutto a causa del segno diverso (il risultato del calcolo è + infinito, il risultato corretto è -100000000000000000000.0).

Si potrebbe ancora dire che non importa davvero perché entrambi hanno torto. La cosa importante è che ci sono molte applicazioni numeriche in cui il risultato più importante del calcolo è il segno, ad esempio quando si decide se girare a sinistra o a destra all'incrocio usando un algoritmo di apprendimento automatico, è possibile interpretare un valore positivo => turn sinistra, valore negativo => gira a destra, la "grandezza" effettiva del valore è solo "coefficiente di confidenza".


Hai qualche idea sul fatto che il segno di underflow possa essere particolarmente importante nei calcoli numerici immaginari / complessi?
jpmc26,

@qbd: sai quali sono queste applicazioni numeriche? Direi che i programmi che si attivano e che utilizzano +infe -infnel normale funzionamento sono disturbati.
Björn Lindqvist,

@ BjörnLindqvist Se vuoi applicazioni scaricabili concrete, allora non ne conosco nessuna. Non penso che sia necessariamente buggy - invece di float / double potresti usare qualcosa come BigDecimal con precisione illimitata. Ma ne vale la pena quando il programma darà esattamente gli stessi risultati di quello con float / double, ma con prestazioni molto peggiori?
qbd,

Hai scritto "applicazioni numeriche in cui il risultato più importante del calcolo è il segno" Posso crederlo, ma non posso credere che ci siano applicazioni ben scritte che si basano su -0 e sui valori essere +infe -inf. Se il tuo programma causa underflow in virgola mobile, questo è il bug e ciò che succede dopo non è così interessante, imho. Ci mancano ancora esempi pratici in cui -0 è utile.
Björn Lindqvist,

1
@ BjörnLindqvist Gran parte di x265 viene eseguita in assembly, basandosi sui suoi dettagli oscuri (che dipendono dall'architettura della CPU) di cui pochi conoscono in nome delle prestazioni. È sbagliato? Affidarsi allo standard di 30 anni ampiamente implementato (che è qui per restare) per una caratteristica semplice e ben compresa in nome della performance improvvisamente non sembra così male.
qbd,

8

Innanzitutto, come si crea un -0? Esistono due modi: (1) eseguire un'operazione in virgola mobile in cui il risultato matematico è negativo, ma così vicino a zero che viene arrotondato a zero e non a un numero diverso da zero. Questo calcolo darà un -0. (b) Determinate operazioni che comportano zeri: moltiplicare uno zero positivo per un numero negativo o dividere uno zero positivo per un numero negativo o annullare uno zero positivo.

Avere uno zero negativo semplifica un po 'la moltiplicazione e la divisione, il segno di x * yo x / y è sempre il segno di x, esclusivo o il segno di y. Senza zero negativo, ci dovrebbe essere un controllo extra per sostituire -0 con +0.

Ci sono alcune situazioni molto rare in cui è utile. Puoi verificare se il risultato di una moltiplicazione o divisione è matematicamente maggiore o minore di zero, anche se c'è un underflow (purché tu sappia che il risultato non è uno zero matematico). Non ricordo di aver mai scritto codice in cui fa la differenza.

Ottimizzare i compilatori odia -0. Ad esempio, non è possibile sostituire x + 0.0 con x, poiché il risultato non dovrebbe essere x se x è -0.0. Non puoi sostituire x * 0.0 con 0.0, perché il risultato dovrebbe essere -0.0 se x <0 o x è -0.0.


7
Vorrei che IEEE-754 avesse incluso quattro zeri: "esatto", infinitesimale positivo, infinitesimale negativo e senza segno (quest'ultimo essendo la differenza tra valori indistinguibili). In questo modo avrebbero funzionato molti assiomi a virgola mobile - tra questi, x + 0,0 equiv x-0,0 equiv x, xy equiv x + (- 1,0) * y e 1,0 / x equiv -1,0 / (- 1,0 * x) [se x è zero positivo, entrambi sarebbero pos-inf; se neg-zero, entrambi neg-inf; se esatto o non firmato, entrambi NaN].
supercat,

Sono stato in grado di ottenere uno zero negativo passando -5e 5dentro fmod(). È abbastanza fastidioso per il mio caso d'uso.
Aaron Franke,

6

Doppio C # conforme a IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

stampe:

Infinity
-Infinity

in realtà per spiegare un po '...

Double d = -0.0; 

Questo significa qualcosa di molto più vicino a d = The Limit of x as x approaches 0-o The Limit of x as x approaches 0 from the negatives.


Per rispondere al commento di Philipp ...

Lo zero sostanzialmente negativo significa underflow.

C'è uno scarso utilizzo pratico per zero negativo se presente ...

ad esempio, questo codice (di nuovo C #):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

produce questo risultato:

True
True
0

Per spiegare in modo informale, tutti i valori speciali che un IEEE 754 in virgola mobile può avere (infinito positivo, infinito negativo, NAN, -0,0) non hanno significato in senso pratico. Non possono rappresentare alcun valore fisico o alcun valore che abbia senso nel calcolo del "mondo reale". Ciò che significano è fondamentalmente questo:

  • l'infinito positivo indica un overflow all'estremità positiva che può rappresentare un punto mobile
  • l'infinito negativo indica un overflow all'estremità positiva che può rappresentare un punto mobile
  • zero negativo significa un underflow e gli operandi avevano segni opposti
  • zero positivo può significare un underflow e gli operandi avevano lo stesso segno
  • NAN significa che il tuo calcolo è indefinitamente definito, simile sqrt(-7)o che non ha un limite simile 0/0o similePositiveInfinity/PositiveInfinity

7
Sì, ma perché è importante? Puoi fornire un esempio pratico e reale in cui la differenza conta?
Philipp

5

La domanda su come ciò si riferisce ai calcoli di numeri complessi è davvero al centro del motivo per cui sia +0 che -0 esistono in virgola mobile. Se studi affatto l'Analisi Complessa, scopri rapidamente che le funzioni continue da Complesso a Complesso di solito non possono essere trattate come "a valore singolo" a meno che non si adotti la "finzione educata" che gli output formano quella che è conosciuta come una "superficie di Riemann". Ad esempio, il logaritmo complesso assegna ad ogni input infinitamente molte uscite; quando li "colleghi" per formare un output continuo, finisci con tutte le parti reali che formano una superficie di "cavatappi infinito" attorno all'origine. Una curva continua che attraversa l'asse reale "verso il basso dal lato positivo-immaginario" e un'altra curva che "avvolge il polo" e attraversa l'asse reale "

Ora applicalo a un programma numerico che calcola usando il virgola mobile complesso. L'azione intrapresa dopo un determinato calcolo può essere molto diversa a seconda di quale "foglio" il programma è attualmente "attivo", e il segno dell'ultimo risultato calcolato probabilmente indica quale "foglio". Supponiamo ora che il risultato sia zero? Ricorda, qui "zero" significa davvero "troppo piccolo per rappresentare correttamente". Ma se il calcolo è in grado di organizzare la conservazione del segno (ovvero ricordare quale 'foglio') quando il risultato è zero, il codice può controllare il segno ed eseguire l'azione giusta anche in questa situazione.


1

Il motivo è più semplice del solito

Naturalmente ci sono molti hack che sembrano davvero belli e sono utili (come arrotondare a -0.0o +0.0ma supponiamo che all'inizio abbiamo una rappresentazione di int firmato con un segno meno / più (so che è stato risolto dal codice binario U2 in numeri interi di solito, ma assume una rappresentazione meno complessa del doppio):

0 111 = 7
^ sign

E se c'è un numero negativo?

1 111 = -7

Va bene, così semplice. Quindi rappresentiamo 0:

0 000 = 0

Anche questo va bene. Ma che dire 1 000? Deve essere un numero proibito? Meglio di no.

Supponiamo quindi che ci siano due tipi di zero:

0 000 = +0
1 000 = -0

Bene, questo semplificherà i nostri calcoli e fornirà alcune funzionalità aggiuntive. Quindi gli +0e -0provengono solo da problemi di rappresentazione binaria.


6
Se sto leggendo questo correttamente, essenzialmente stai solo dicendo che le persone che definiscono o implementano gli standard non volevano preoccuparsi di vietarlo. Non penso che questo ragionamento sostenga che il complemento di 2 utilizza la rappresentazione "zero negativo" per un numero completamente diverso e non ha rappresentazione di zero negativo. Vedi l'articolo di Wikipedia che ho collegato.
jpmc26,

1
@ jpmc26 Penso che in realtà ci sia un po 'di verità in questo, in quanto non proibirlo significa non richiedere implementazioni per avere un caso speciale. Così com'è, ogni numero ha un bit di segno e può essere negato attivando il bit di segno. Anche i NaN sono firmati e le implementazioni possono (ma non sono obbligate a) scegliere un segno appropriato durante la produzione di un NaN. Se lo zero negativo non esistesse, ogni calcolo che ha portato a 0 avrebbe bisogno di fare un lavoro extra per sistemare il bit di segno, ecc.
hobbs

4
@ jpmc26 (ovvero in ogni altra moltiplicazione di due numeri, il segno del risultato è il xor del segno dei moltiplicatori e la grandezza è il prodotto delle due magnitudini. Nella vita reale funziona per -1 * 0 = - 0. Ma se zero con il bit di segno capovolto fosse un valore speciale diverso da zero, ogni prodotto che potrebbe produrre 0 dovrebbe verificare e assicurarsi che non produca per errore quel valore speciale.)
hobbs
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.