Architetture esotiche a cui tengono i comitati degli standard


154

So che gli standard C e C ++ lasciano molti aspetti dell'implementazione del linguaggio definiti solo perché se esiste un'architettura con altre caratteristiche, sarebbe molto difficile o impossibile scrivere un compilatore conforme allo standard.

So che 40 anni fa ogni computer aveva le sue specifiche uniche. Tuttavia, non conosco alcuna architettura utilizzata oggi dove:

  • CHAR_BIT != 8
  • signed non è un complemento a due (ho sentito che Java ha avuto problemi con questo).
  • Il virgola mobile non è conforme a IEEE 754 (Modifica: intendevo "non nella codifica binaria IEEE 754").

Il motivo per cui lo sto chiedendo è che spesso spiego alle persone che è positivo che il C ++ non imponga altri aspetti di basso livello come i tipi di dimensioni fisse . È buono perché, a differenza di "altre lingue", rende il codice portatile se usato correttamente (Modifica: perché può essere portato su più architetture senza richiedere l'emulazione di aspetti di basso livello della macchina, come ad esempio l'aritmetica del complemento a due sul segno + architettura magnitudo) . Ma mi sento male per il fatto che non posso indicare nessuna specifica architettura da solo.

Quindi la domanda è: quali architetture presentano le proprietà sopra?

uint*_ts sono opzionali.


9
Penso che tu l'abbia al contrario. Se il C ++ dovesse imporre, diciamo, due complementi per numeri interi con segno, renderebbe il codice C ++ più portabile non meno. La questione del perché il comitato per gli standard C ++ non imponga questo è un'altra questione. Soprattutto perché, nonostante ciò che dici, non sarebbe impossibile scrivere un compilatore per un'architettura non standard, puoi sempre simulare caratteri a 8 bit o due complementi aritmetici anche quando la tua piattaforma non lo supporta direttamente.
Giovanni,

8
@john: allora sarebbe impraticabile, quindi un compilatore non standard conforme genererebbe un codice più veloce di uno conforme. E ancora non vedo come rende il tuo codice più portatile.
Yakov Galka,

4
Sono sicuro che la vera ragione per cui lo standard è così non è perché è una soluzione ideale. Ma invece è perché quando lo standard è stato scritto molti compilatori C e C ++ esistevano già e il comitato degli standard non voleva rifiutare i compilatori esistenti.
Giovanni,

4
@john: Dubito che "rendere più facile per gli autori di compilatori" sia una priorità quando si crea lo standard C ++ (farebbero un lavoro terribile se lo fosse, dal momento che C ++ è uno dei linguaggi più difficili da analizzare, e altri aspetti di il linguaggio non lo rende esattamente facile nemmeno per gli autori di compilatori). Tuttavia, le prestazioni, il supporto di un'ampia piattaforma e la compatibilità con le versioni precedenti sono piuttosto importanti. E tutti e tre soffrirebbero se le restrizioni che menzionate fossero aggiunte allo standard.
Sander De Dycker,

5
Non si tratta del compilatore ma dell'hardware. Il C ++ lascia alcune cose non specificate per consentire l'uso diretto delle funzionalità hardware. Le app del tuo telefono non funzioneranno comunque su un mainframe, quindi non c'è portabilità per quanto sia conforme il codice.
Bo Persson,

Risposte:


114

Dai un'occhiata a questo

Server Unisys ClearPath Dorado

offrendo compatibilità con le versioni precedenti per le persone che non hanno ancora migrato tutto il loro software Univac.

Punti chiave:

  • Parole a 36 bit
  • CHAR_BIT == 9
  • complemento
  • Virgola mobile non IEEE a 72 bit
  • spazio indirizzo separato per codice e dati
  • word-indirizzata
  • nessun puntatore dello stack dedicato

Non so se offrono un compilatore C ++, ma potrebbero .


E ora è emerso un collegamento a una recente edizione del loro manuale C:

Manuale di riferimento per la programmazione del compilatore C Unisys

La sezione 4.5 ha una tabella di tipi di dati con 9, 18, 36 e 72 bit.

dimensione e intervallo di tipi di dati nel compilatore USC C.


13
Immagino che il vuoto * debba essere infernale da usare in quell'architettura.
luiscubal,

13
@ybungalobill - Credo char*che void*debba avere le stesse dimensioni e abbastanza grande da contenere qualsiasi altro puntatore. Il resto dipende dall'implementazione.
Bo Persson,

22
@ybungalobill: sui vecchi compilatori Win16, i puntatori regolari erano vicini ai puntatori e contenevano solo un offset a 16 bit, quindi sizeof(int*) == 2, ma i puntatori lontani avevano anche un selettore a 16 bit, quindi sizeof(void*) == 4.
Adam Rosenfield,

10
Esiste, o esisteva, un manuale online per il proprio compilatore C ++. Vale anche la pena sottolineare che questa è solo una delle architetture mainframe di Unisys: l'altra è un'architettura con tag di magnitudine firmata a 48 bit (per la quale ho trovato solo un manuale C, non uno C ++). Per il resto: non penso che sizeof(int*) != sizeof(char*)qui: entrambi sono 36 bit. Ma il selettore di byte in char*è sui bit di ordine superiore e viene ignorato in int*. (Ho usato altre macchine, tuttavia, dove `sizeof (char *)> sizeof (int *).)
James Kanze,

16
@Adam Rosenfield Sui compilatori MS / DOS a 16 bit, c'erano "modalità" diverse e i puntatori di dati non avevano necessariamente le stesse dimensioni dei puntatori di funzione. Ma almeno su quelli che ho usato, tutti i puntatori di dati (incluso void*) avevano sempre le stesse dimensioni. (Naturalmente, non è possibile convertire un puntatore a funzione in void*, poiché void*potrebbe essere più piccolo. Ma secondo lo standard, non è possibile farlo neanche oggi.)
James Kanze,

51

Nessuna delle tue ipotesi vale per i mainframe. Per i principianti, non conosco un mainframe che utilizza IEEE 754: IBM utilizza la virgola mobile base 16 ed entrambi i mainframe Unisys usano la base 8. Le macchine Unisys sono un po 'speciali sotto molti altri aspetti: Bo ha menzionato il 2200 architettura, ma l'architettura MPS è ancora più strana: parole con tag a 48 bit. (Se la parola è un puntatore o meno dipende da un bit nella parola.) E le rappresentazioni numeriche sono progettate in modo tale che non vi sia alcuna reale distinzione tra punto mobile e aritmetica integrale: il punto mobile è base 8; non richiede normalizzazione e, diversamente da ogni altro punto fluttuante che ho visto, mette il decimale a destra della mantissa, piuttosto che a sinistra, e usa la magnitudine firmata per l'esponente (oltre alla mantissa). Con i risultati che un valore in virgola mobile integrale ha (o può avere) esattamente la stessa rappresentazione di bit di un intero di magnitudine con segno. E non ci sono istruzioni aritmetiche in virgola mobile: se gli esponenti dei due valori sono entrambi 0, l'istruzione fa l'aritmetica integrale, altrimenti fa l'aritmetica in virgola mobile. (Una continuazione della filosofia di tagging nell'architettura.) Ciò significa che mentreint può occupare 48 bit, 8 di questi devono essere 0 o il valore non verrà trattato come un numero intero.


4
I mainframe IBM (z / Architecture) supportano IEE754 in virgola mobile.
Nikita Nemkin,


6
@Nikita - Lo fanno ora . Inizialmente era un (costoso) componente aggiuntivo per supportare Java.
Bo Persson,


42

La piena conformità IEEE 754 è rara nelle implementazioni in virgola mobile. E indebolire le specifiche in tal senso consente molte ottimizzazioni.

Ad esempio, il supporto subnorm differisce tra x87 e SSE.

Ottimizzazioni come la fusione di una moltiplicazione e aggiunta che erano separate nel codice sorgente cambiano leggermente anche i risultati, ma è una buona ottimizzazione su alcune architetture.

O su x86 una rigorosa conformità IEEE potrebbe richiedere l'impostazione di alcuni flag o trasferimenti aggiuntivi tra i registri a virgola mobile e la memoria normale per forzare l'utilizzo del tipo a virgola mobile specificato anziché i suoi galleggianti interni a 80 bit.

E alcune piattaforme non hanno alcun float hardware e quindi devono emularle nel software. E alcuni dei requisiti di IEEE 754 potrebbero essere costosi da implementare nel software. In particolare, le regole di arrotondamento potrebbero essere un problema.

La mia conclusione è che non hai bisogno di architetture esotiche per entrare in situazioni in cui non vuoi sempre garantire la rigorosa conformità IEEE. Per questo motivo pochi linguaggi di programmazione garantiscono una rigorosa conformità IEEE.


7
Un altro set "esotico" di hardware sono i mainframe IBM in cui il formato a virgola mobile precede lo standard IEEE. A differenza di Java, C ++ può ancora utilizzare l'hardware esistente.
Bo Persson,

5
IEEE 754 non è completamente supportato dalle GPU.
Kerem,

3
La mancanza di una rigorosa conformità a IEEE 754 è una seccatura per alcuni, ma non penso che rientri nell'ambito delle questioni a cui l'OP si preoccupa davvero.
Onnipotente il

3
@Matthieu Dato che anche questo è etichettato "C", dovrei menzionare un analizzatore C che può dirti tutti i valori che il tuo programma a virgola mobile può prendere con i registri a virgola mobile a 80 bit versati in memoria per capriccio del compilatore C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq

2
@MatthieuM .: Peccato che ISO / ANSI non abbia consentito ai parametri variadici di specificare dimensioni minime / massime per argomenti a virgola mobile e interi; se così fosse, l'80 bit long doubleavrebbe potuto essere un tipo utile e di lunga durata, dal momento che l'unico vero problema era che funziona male printf. Il fatto che il doppio esteso memorizzi il 1 principale accelera esplicitamente i calcoli su sistemi non FPU ed eliminerebbe anche la necessità di una gestione speciale dei denormali in qualsiasi contesto diverso dalle conversioni da / verso altri tipi. Peccato che C abbia printfincasinato tutto.
supercat

40

Ho trovato questo link che elenca alcuni sistemi in cui CHAR_BIT != 8. Loro includono

alcuni DSP TI hanno CHAR_BIT == 16

Chip BlueCore-5 (un chip Bluetooth della Cambridge Silicon Radio) che ha CHAR_BIT == 16.

E ovviamente c'è una domanda su Stack Overflow: quali piattaforme hanno qualcosa di diverso dal char a 8 bit

Per quanto riguarda i sistemi non a complemento a due c'è una lettura interessante su comp.lang.c ++. Moderata . Riassumendo: ci sono piattaforme che hanno il proprio complemento o segno e rappresentazione della grandezza.


5
Analog Devices a 32 bit SHARC DSP CHAR_BIT=32e Texas Instruments DSP di TMS32F28xx CHAR_BIT=16. GCC 3.2 per PDP-10 ha CHAR_BIT=9. Penso che S / 360 potrebbe anche avere un carattere non a 8 bit.
Osgx,

1
Vorrei ancora un esempio per le architetture del "non complemento a due". Soprattutto da quando è successo che si CHAR_BITStratta di un duplicato parziale.
Yakov Galka,

I DSP TI hanno caratteri a 16 bit solo perché gli implementatori l'hanno scelto (sarebbe un po 'più lavoro per farlo funzionare bene, ma IIRC non assurdamente duro - probabilmente solo alcuni "buchi" nello scaffale codegen nel compilatore sottostante) . Quindi non è una ragione architettonica profonda. Il codice C funziona su una macchina astratta. Se hai solo INT a 16 bit, memorizza due caratteri in ciascuno e aggiungi l'unione read-edit-write all'ottimizzatore spioncino (almeno). Certo, è più lavoro, ma guarda quanto più lavoro è per tutti per affrontare tali tipi strani in luoghi in cui non verranno mai mostrati. Che schifo.
Ripristina Monica il

24

Sono abbastanza sicuro che i sistemi VAX siano ancora in uso. Non supportano IEEE in virgola mobile; usano i loro formati. Alpha supporta i formati a virgola mobile VAX e IEEE.

Anche le macchine vettoriali Cray, come la T90, hanno il loro formato in virgola mobile, sebbene i sistemi Cray più recenti utilizzino IEEE. (Il T90 che ho usato è stato messo fuori servizio alcuni anni fa; non so se ce ne siano ancora in uso.)

Il T90 aveva anche / ha alcune rappresentazioni interessanti per puntatori e numeri interi. Un indirizzo nativo può puntare solo a una parola a 64 bit. I compilatori C e C ++ avevano CHAR_BIT == 8 (necessario perché eseguiva Unicos, un tipo di Unix, e dovevano interagire con altri sistemi), ma un indirizzo nativo poteva solo indicare una parola a 64 bit. Tutte le operazioni a livello di byte sono stati sintetizzati dal compilatore, e una void*o char*immagazzinato un offset high ordine 3 bit della parola byte. E penso che alcuni tipi interi abbiano bit di riempimento.

I mainframe IBM sono un altro esempio.

D'altro canto, questi sistemi particolari non devono necessariamente escludere modifiche allo standard linguistico. Cray non ha mostrato alcun interesse particolare nell'aggiornamento del suo compilatore C a C99; presumibilmente la stessa cosa si applicava al compilatore C ++. Esso potrebbe essere ragionevole per stringere i requisiti per implementazioni in hosting, come la richiesta CHAR_BIT == 8, formato IEEE in virgola mobile, se non la semantica pieno, e 2's-complemento senza bit di riempimento per gli interi con segno. I vecchi sistemi potrebbero continuare a supportare gli standard linguistici precedenti (C90 non è morto quando è uscito il C99) e i requisiti potrebbero essere più flessibili per le implementazioni indipendenti (sistemi integrati) come i DSP.

D'altra parte, potrebbero esserci buone ragioni per i sistemi futuri di fare cose che oggi sarebbero considerate esotiche.


6
Un buon punto alla fine su come standard troppo rigidi impediscono l'innovazione. Quando avremo computer quantistici (o organici) con stati trinitari, i requisiti aritmetici del modulo per i unsignedtipi integrali saranno un grande dolore, mentre l'aritmetica firmata andrà bene.
Ben Voigt,

@BenVoigt Perché l'aritmetica senza segno è un dolore? Non è possibile aggiungere moduli 3 ^ n in quei computer?
phuclv,

2
@ LưuVĩnhPhúc: questo è esattamente il punto, con le operazioni hardware eseguite modulo 3 ** n, fornendo tipi senza segno C ++ le cui operazioni sono definite modulo 2 ** n saranno difficili.
Ben Voigt,

2
Conosco un VAX 11/780 ancora in uso come host per un compilatore incrociato destinato a un sistema embedded specializzato con un'architettura proprietaria. Per sostenere quel particolare VAX, i custodi si sono avvicinati ai musei per ottenere ricambi.
Peter,

2
@Keith: tecnicamente, l'unico ostacolo sta attraversando un processo per fornire prove in grado di soddisfare i requisiti normativi, poiché il sistema incorporato di destinazione è altamente critico. Vi sono tuttavia numerosi ostacoli non tecnici (politica organizzativa, ecc.) Che finora sono stati insormontabili. Attualmente è più semplice montare un caso per razziare i musei che aggiornare l'host.
Peter,

16

CHAR_BITS

Secondo il codice sorgente di gcc :

CHAR_BITè 16bit per architetture 1750a , dsp16xx .
CHAR_BITè 24bit per l' architettura dsp56k .
CHAR_BITsono 32bit per l' architettura c4x .

Puoi facilmente trovare altro facendo:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

o

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

se CHAR_TYPE_SIZEè definito in modo appropriato.

Conformità IEEE 754

Se l'architettura di destinazione non supporta le istruzioni in virgola mobile, gcc può generare un fallback software che non è lo standard conforme per impostazione predefinita. -funsafe-math-optimizationsInoltre, è possibile utilizzare opzioni speciali (come strega che disabilita anche la conservazione dei segni per gli zeri).


3
votato per aver semplicemente diretto l'OP a guardare la fonte di un popolare compilatore; questa è la definizione di RFTM in questo caso, quindi dovrebbe essere il primo posto in cui le persone guardano.
underscore_d

9

La rappresentazione binaria IEEE 754 era rara sulle GPU fino a poco tempo fa, vedi Paranoia a virgola mobile GPU .

EDIT: nei commenti è stata sollevata una domanda se la virgola mobile della GPU sia rilevante per la normale programmazione informatica, non correlata alla grafica. Diavolo sì! La maggior parte delle prestazioni ad alte prestazioni calcolate oggi a livello industriale viene eseguita su GPU; l'elenco include AI, data mining, reti neurali, simulazioni fisiche, previsioni meteorologiche e molto altro ancora. Uno dei collegamenti nei commenti mostra perché: un vantaggio in ordine di grandezza in virgola mobile delle GPU.

Un'altra cosa che vorrei aggiungere, che è più rilevante per la domanda OP: cosa hanno fatto le persone 10-15 anni fa quando la virgola mobile della GPU non era IEEE e quando non c'erano API come OpenCL o CUDA di oggi per programmare le GPU? Che ci crediate o no, i primi pionieri dell'informatica GPU sono riusciti a programmare GPU senza un'API per farlo ! Ne ho incontrato uno nella mia compagnia. Ecco cosa ha fatto: ha codificato i dati necessari per calcolare come immagine con pixel che rappresentano i valori su cui stava lavorando, quindi ha usato OpenGL per eseguire le operazioni di cui aveva bisogno (come "sfocatura gaussiana" per rappresentare una convoluzione con una distribuzione normale , ecc.) e decodificato l'immagine risultante in una serie di risultati. E questo era ancora più veloce dell'uso della CPU!

Cose del genere sono ciò che ha spinto NVidia a rendere finalmente i loro dati binari interni compatibili con IEEE e ad introdurre un'API orientata al calcolo piuttosto che alla manipolazione delle immagini.


In che modo sono rilevanti le GPU? (a) Questa pagina sembra molto obsoleta. (b) Fino ad oggi non è possibile programmare GPU in C: perché C supporta cose come funzioni ricorsive che le GPU, per quanto ne sappia, non lo fanno. Quindi non puoi nemmeno scrivere un compilatore se lo desideri.
Yakov Galka,

1
@ybungalobill, scaricare il lavoro ripetitivo su GPU è attualmente il metodo preferito per i calcoli su larga scala . In effetti, ne sto attualmente sviluppando uno in C ++. Fortunatamente, lavoriamo solo con GPU NVidia CUDA che hanno una rappresentazione binaria compatibile con IEEE 754 di float.
Michael,

Non dico che le GPU non vengano utilizzate per i calcoli GP. Ho detto che non programmate davvero i kernel in C, nonostante la somiglianza di sintassi. Puoi eseguire int f(int n) { return n <= 1 ? 1 : n * f(n-1); }in CUDA? In caso contrario, le GPU non sono rilevanti per questa domanda (che chiede informazioni sui comitati C e C ++).
Yakov Galka,

6
@ybungalobill: diverse risposte a questo. Innanzitutto, CUDA supporta C, C ++ e Fortran . Vedi lo stesso link per l'enorme vantaggio prestazionale delle GPU a 2048 thread rispetto alla tua tipica CPU a 8 thread. In secondo luogo, sono supportati solo sottoinsiemi (sebbene di grandi dimensioni) di tali lingue, inclusa la mancanza di supporto per la ricorsione del modello di programmazione CUDA (chiamato "parallelismo dinamico") fino a CUDA 5.0. In terzo luogo, le ricorsioni possono di solito essere sostituite da anelli, che sono comunque necessari per le prestazioni multithread.
Michael,
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.