Come può un virgola mobile a 80 bit essere utilizzato da un sistema a 32 bit? [duplicare]


13

Poiché un sistema a 32 bit non è in grado di gestire un numero 2 ^ 33 (a causa dell'ovvio limite a 32 bit), come può gestire un numero in virgola mobile a 80 bit ?

Dovrebbe richiedere "80-bit" ...


8
Allo stesso modo fa un numero in virgola mobile a 64 bit. Utilizza 3 o (2) registri a 32 bit. Poiché il numero in virgola mobile a 80 bit non è nemmeno una dimensione standard, in realtà sarebbe un numero a 96 bit con solo 80 bit utilizzati.
Ramhound,

5
quando ti preoccupi della mancanza di piattaforma, sei preoccupato del funzionamento interno della CPU, come altri hanno già detto, e del modo in cui le istruzioni vengono eseguite nativamente sul sistema. I numeri IEEE754 sono di solito direttamente elaborabili nelle unità di esecuzione FPU della CPU, mentre un numero a 128 bit richiederebbe l'uso di più istruzioni programmate in modo tale da poter aggregare il significato del valore che l'applicazione sta valutando. che lascia l'elaborazione del numero fino all'applicazione.
Frank Thomas,

2
@ Ƭᴇcʜιᴇ007 Non proprio un controtipo di che uno. Quello riguarda più la differenza tra un numero e la sua rappresentazione di testo / ASCII, anche se alcune di quelle risposte potrebbero anche risolvere questo problema.
Bob

3
In quasi tutte le macchine moderne, la virgola mobile è gestita da un processore separato (sebbene di solito si trovi sullo stesso chip del processore principale). Tutti questi processori sanno come gestire gli 80 bit (anche se alcuni lo fanno molto più velocemente di altri). ( E la "larghezza" di un processore è comunque una sorta di finzione. )
Daniel R Hicks,

6
@Ramhound: No, 80 bit è una peculiarità 8087 e utilizza 1 registro FP. Non è sicuramente un numero di 96 bit.
Salterio

Risposte:


35

Uno dei significati di una CPU a 32 bit è che i suoi registri sono larghi 32 bit. Ciò non significa che non possa gestire i numeri di 64 bit, ma solo che deve occuparsi prima della metà inferiore a 32 bit, quindi della seconda metà superiore a 32 bit. (È per questo che le CPU hanno un flag carry .) È più lento che se la CPU potesse semplicemente caricare i valori in un registro più ampio a 64 bit, ma è ancora possibile.

Pertanto, il "testimone" di un sistema non limita necessariamente la dimensione dei numeri che un programma può gestire, poiché è sempre possibile interrompere le operazioni che non rientrano nei registri della CPU in più operazioni. Quindi rende le operazioni più lente, consuma più memoria (se devi usare la memoria come "scratchpad") e più difficile da programmare, ma le operazioni sono ancora possibili.

Tuttavia, nulla di tutto ciò conta, ad esempio, con processori Intel a 32 bit e virgola mobile, poiché la parte in virgola mobile della CPU ha i suoi registri e sono larghi 80 bit. (All'inizio della storia dell'x86, la capacità in virgola mobile era un chip separato, era integrato nella CPU a partire da 80486DX.)


La risposta di @ Breakthrough mi ha ispirato ad aggiungere questo.

I valori in virgola mobile, nella misura in cui sono memorizzati nei registri FPU, funzionano in modo molto diverso dai valori interi binari.

Gli 80 bit di un valore in virgola mobile sono divisi tra una mantissa e un esponente (c'è anche la "base" nei numeri in virgola mobile che è sempre 2). La mantissa contiene le cifre significative e l'esponente determina quanto sono grandi quelle cifre significative. Quindi non c'è "overflow" in un altro registro, se il tuo numero diventa troppo grande per adattarsi alla mantissa, il tuo esponente aumenta e perdi precisione - cioè quando lo converti in un numero intero, perdi i decimali a destra - ecco perché si chiama virgola mobile.

Se il tuo esponente è troppo grande, hai un overflow in virgola mobile, ma non puoi facilmente estenderlo ad un altro registro poiché l'esponente e la mantissa sono legati insieme.

Potrei essere inesatto e sbagliato su un po 'di questo, ma credo che sia questo il senso. (Questo articolo di Wikipedia illustra un po 'più succintamente quanto sopra).

Va bene che questo funziona in modo totalmente diverso dal momento che l'intera parte "a virgola mobile" della CPU è in un certo senso nel suo mondo: per accedervi e usi simili istruzioni CPU speciali. Inoltre, verso il punto della domanda, poiché è separato, il testimone della FPU non è strettamente associato al testimone della CPU nativa.


4
Tutto ciò che hai aggiunto dalla mia ispirazione è corretto, quindi non preoccuparti :) Un solo punto che dovrei menzionare, anche se puoi usare istruzioni CPU native dove esiste un'unità a virgola mobile, puoi anche eseguire operazioni a virgola mobile nel software (con bit a bit equivalente o operazioni matematiche intere). Per estendersi fino a quel punto, data la memoria sufficiente, puoi anche avere numeri di precisione arbitrari (al contrario dei nostri fissi 64-bit, o 80-bit in questo caso) usando algoritmi / librerie software (uno comunemente usato è il GNU Multiple Precision biblioteca ).
Breakthrough

1
Nitpick: la prima FPU integrata Intel era nell'80486DX, non nell'80386.
Spudone,

2
@markzzz: Nulla è pazzo se è richiesto. L'uso di galleggianti a 16 bit per simulare una bomba atomica al fine di valutare le tue scorte nucleari è pazzesco perché non è abbastanza preciso per essere sicuro del risultato. Nel qual caso sono richiesti 32 bit (e sì, ai vecchi tempi questi calcoli venivano eseguiti su PDP a 16 bit). Allo stesso modo, l'utilizzo di folati a 32 bit per simulare il clima non è abbastanza preciso a causa della natura caotica dei calcoli.
Slebetman,

2
FWIW, il modo comune per implementare operazioni in virgola mobile su macchine senza unità FP delle dimensioni desiderate è farlo nel software usando le istruzioni intere. Perché, alla fine della giornata, sia l'esponente che la mantissa del numero in virgola mobile sono semplicemente numeri interi. È il modo in cui li interpretiamo che dà loro i loro significati speciali.
slebetman

2
@PTwr su x86 in realtà hai 7 GPR utilizzabili per i dati, incluso EBP. È solo che l'ABI della maggior parte delle implementazioni linguistiche riserva questo registro per il puntatore dello stack frame. Ma ad esempio con GCC puoi usare -fomit-frame-pointerper riavere quel registro.
Ruslan,

13

32-bit, 64-bit e 128-bit si riferiscono tutti alla lunghezza della parola del processore, che può essere considerata il "tipo di dati fondamentale". Spesso, questo è il numero di bit trasferiti da / verso la RAM del sistema e la larghezza dei puntatori (anche se nulla ti impedisce di utilizzare il software per accedere a più RAM di quello a cui un singolo puntatore può accedere).

Supponendo che una velocità di clock costante (così come tutto il resto nell'architettura sia costante) e supponendo che letture / scritture di memoria abbiano la stessa velocità (ipotizziamo 1 ciclo di clock qui, ma questo è lontano dal caso nella vita reale), puoi aggiungi due numeri a 64 bit in un singolo ciclo di clock su un computer a 64 bit (tre se conti il ​​recupero dei numeri dalla RAM):

ADDA [NUM1], [NUM2]
STAA [RESULT]

Possiamo anche fare lo stesso calcolo su una macchina a 32 bit ... Tuttavia, su una macchina a 32 bit, dobbiamo farlo nel software, poiché prima devono essere aggiunti i 32 bit inferiori, compensare l'overflow, quindi aggiungere i 64 bit superiori:

     ADDA [NUM1_LOWER], [NUM2_LOWER]
     STAA [RESULT_LOWER]
     CLRA          ; I'm assuming the condition flags are not modified by this.
     BRNO CMPS     ; Branch to CMPS if there was no overflow.
     ADDA #1       ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
     STAA [RESULT_UPPER]

Analizzando la mia sintassi dell'assembly inventato, puoi facilmente vedere come operazioni di precisione più elevata possono richiedere un tempo esponenzialmente più lungo su una macchina di lunghezza inferiore. Questa è la vera chiave dei processori a 64 e 128 bit: ci consentono di gestire un numero maggiore di bit in una singola operazione. Alcune macchine includono istruzioni per aggiungere altre quantità con un carry (ad esempio ADCsu x86), ma l'esempio sopra ha in mente valori di precisione arbitrari.


Ora, per estenderlo alla domanda, è semplice vedere come potremmo aggiungere numeri più grandi dei registri che abbiamo a disposizione - abbiamo semplicemente suddiviso il problema in blocchi delle dimensioni dei registri e lavoriamo da lì. Sebbene, come menzionato da @MatteoItalia , lo stack FPU x87 abbia un supporto nativo per quantità a 80 bit, nei sistemi privi di questo supporto (o nei processori privi di un'unità in virgola mobile!), I calcoli / operazioni equivalenti devono essere eseguiti nel software .

Quindi, per un numero a 80 bit, dopo aver aggiunto ciascun segmento a 32 bit, verificherebbe anche l'overflow nel bit 81 e, se lo si desidera, azzerare i bit di ordine superiore. Questi controlli / zeri vengono eseguiti automaticamente per determinate istruzioni x86 e x86-64, dove vengono specificate le dimensioni degli operandi di origine e destinazione (sebbene siano specificate solo in potenze di 2 a partire da 1 byte di larghezza).

Naturalmente, con numeri in virgola mobile, non si può semplicemente eseguire l'aggiunta binaria poiché la mantissa e le cifre significative sono raggruppate insieme in forma offset. Nell'ALU su un processore x86, esiste un circuito hardware per eseguire ciò per i float IEEE a 32 e 64 bit; tuttavia , anche in assenza di un'unità a virgola mobile (FPU), gli stessi calcoli possono essere eseguiti nel software (ad esempio mediante l'uso della GNU Scientific Library , che utilizza una FPU quando compilata su architetture con, ripiegando su algoritmi software se non è disponibile alcun hardware in virgola mobile [ad es. per microcontrollori incorporati privi di FPU]).

Data la memoria sufficiente, si possono anche eseguire calcoli su numeri di precisione arbitraria (o "infinita" - entro limiti realistici), usando più memoria poiché è richiesta maggiore precisione. Un'implementazione di questo esiste nella libreria GNU Multiple Precision , che consente una precisione illimitata (fino a quando la RAM non è piena, ovviamente) su operazioni a numero intero, razionale e in virgola mobile.


2
Non stai menzionando i dettagli più importanti: la FPU x87 sulla piattaforma x86 ha registri a virgola mobile larghi 80 bit, quindi i suoi calcoli nativi vengono effettivamente eseguiti su float a 80 bit, non è necessario emulare nulla nel software.
Matteo Italia,

@MatteoItalia Lo vedo ora, grazie. Pensavo che la domanda originale fosse quella di chiedere una panoramica più generica di come si potevano eseguire operazioni su numeri più grandi della dimensione della parola del processore, e non l'implementazione specifica di float estesi a 80 bit in x86 (anche perché il mio esempio era di 90 bit invece di 80 ...). Ho aggiornato la risposta ora per riflettere meglio questo, grazie per il testa a testa.
Sfondamento

5

L'architettura di memoria del sistema può consentire solo di spostare 32 bit contemporaneamente, ma ciò non gli impedisce di utilizzare numeri più grandi.

Pensa alla moltiplicazione. Potresti conoscere le tue tabelle di moltiplicazione fino a 10x10, ma probabilmente non avrai problemi a eseguire 123x321 su un pezzo di carta: lo spezzerai in molti piccoli problemi, moltiplicando le singole cifre e occupandoti del trasporto ecc.

I processori possono fare la stessa cosa. Ai vecchi tempi c'erano processori a 8 bit che potevano fare matematica in virgola mobile. Ma erano slooooooow.


1
Erano lenti solo dopo un certo punto. Potresti scrivere operazioni in virgola mobile "veloci" se ti limitassi a una determinata specifica.
Ramhound,

3

"32-bit" è davvero un modo di classificare i processori, non una sentenza set-in-stone. un processore "32 bit" in genere ha registri per scopi generali a 32 bit con cui lavorare.

Tuttavia, non esiste un requisito fondamentale per l'esecuzione di tutto nel processore a 32 bit. Ad esempio, non era inaudito che un computer a "32 bit" avesse un bus di indirizzo a 28 bit, perché era più economico realizzare l'hardware. I computer a 64 bit spesso hanno solo un bus di memoria a 40 o 48 bit per lo stesso motivo.

L'aritmetica in virgola mobile è un altro luogo in cui le dimensioni variano. Molti processori a 32 bit supportano numeri in virgola mobile a 64 bit. Lo hanno fatto memorizzando i valori in virgola mobile in registri speciali che erano più ampi dei registri di uso generale. Per memorizzare uno di questi grandi numeri in virgola mobile nei registri speciali, si dovrebbe prima dividere il numero tra due registri di uso generale, quindi emettere un'istruzione per combinarli in un galleggiante nei registri speciali. Una volta in quei registri a virgola mobile, i valori sarebbero manipolati come float a 64 bit, piuttosto che come una coppia di metà a 32 bit.

L'aritmetica a 80 bit che citi è un caso speciale di questo. Se hai lavorato con numeri in virgola mobile, hai familiarità con l'imprecisione derivante da problemi di arrotondamento in virgola mobile. Una soluzione per il roundoff è quella di avere più bit di precisione, ma poi è necessario memorizzare numeri più grandi e forzare gli sviluppatori a utilizzare valori in virgola mobile insolitamente grandi in memoria.

La soluzione Intel è che i registri a virgola mobile sono tutti a 80 bit, ma le istruzioni per spostare i valori da / verso quei registri funzionano principalmente con numeri a 64 bit. Finché si opera interamente all'interno dello stack Intel a virgola mobile x87, tutte le operazioni vengono eseguite con 80 bit di precisione. Se il codice deve estrarre uno di quei valori dai registri a virgola mobile e memorizzarlo da qualche parte, lo tronca a 64 bit.

Morale della storia: categorizzazioni come "32-bit" sono sempre più sfocate quando si approfondiscono le cose!


Ma se uso valori a virgola mobile a 32 bit in un sistema a 16 bit (o valori a virgola mobile a 64 bit in un sistema a 32 bit), richiede solo più memoria (poiché deve registrare due volte)? O l'elaborazione delle informazioni aggiungerà sovraccarico, quindi ci vorrà più tempo?
Markzzz,

@markzzz: lavorare con più registri richiede quasi sempre più tempo
Mooing Duck

Il caricamento del valore in virgola mobile a 32 bit nei registri per scopi speciali richiederà più tempo. Tuttavia, una volta memorizzati come float a 32 bit nei registri a virgola mobile per scopi speciali, l'hardware funzionerà su quei valori in virgola mobile a piena velocità. Ricorda, "16 bit" si riferisce solo alla dimensione dei registri di scopi GENERALI. I registri a virgola mobile sono appositamente dimensionati per il loro compito e possono essere più ampi (32 bit di larghezza nel tuo caso)
Cort Ammon

2

Una CPU a "32 bit" è quella in cui la maggior parte dei registri dei dati sono registri a 32 bit e la maggior parte delle istruzioni opera sui dati in quei registri a 32 bit. È anche probabile che una CPU a 32 bit trasferisca i dati da e verso la memoria a 32 bit alla volta. La maggior parte dei registri essendo a 32 bit non significa che tutti i registri siano a 32 bit. La risposta breve è che una CPU a 32 bit può avere alcune funzionalità che utilizzano altri conteggi, come i registri a virgola mobile a 80 bit e le istruzioni corrispondenti.

Come ha detto @spudone in un commento sulla risposta di @ ultrasawblade, la prima CPU x86 ad avere operazioni in virgola mobile integrate è stata Intel i486 (in particolare l'80486DX ma non l'80486SX), che, secondo la pagina 15-1 dei programmatori a microprocessore i486 Manuale di riferimento , include nei suoi registri numerici "Otto registri numerici a 80 bit indirizzabili individualmente". L'i486 ha un bus di memoria a 32 bit, quindi il trasferimento di un valore di 80 bit richiederebbe 3 operazioni di memoria.

Il predecessore della generazione 486, l'i386, non aveva alcuna operazione in virgola mobile integrata. Invece, aveva il supporto per l'uso di un "coprocessore" a virgola mobile esterno, l'80387. Questo coprocessore aveva quasi la stessa funzionalità integrata nell'i486, come si può vedere dalla pagina 2-1 del Manuale di riferimento del programmatore 80387 .

Il formato a virgola mobile a 80 bit sembra aver avuto origine con l'8087, il coprocessore matematico per 8086 e 8088. Gli 8086 e 8088 erano CPU a 16 bit (con bus di memoria a 16 e 8 bit), ed erano ancora in grado utilizzare il formato a virgola mobile a 80 bit, sfruttando i registri a 80 bit nel coprocessore.

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.