Perché i tipi di numeri interi veloci sono più veloci degli altri tipi di numeri interi?


107

In ISO / IEC 9899: 2018 (C18), è indicato al punto 7.20.1.3:

7.20.1.3 Tipi di numeri interi di larghezza minima più veloci

1 Ciascuno dei seguenti tipi designa un tipo intero che di solito è il più veloce 268) per operare con tutti i tipi interi che hanno almeno la larghezza specificata.

2 Il nome typedef int_fastN_tindica il tipo intero con segno più veloce con una larghezza di almeno N. Il nome typedefuint_fastN_t segno più veloce indica il tipo intero senza segno più veloce con una larghezza di almeno N.

3 Sono richiesti i seguenti tipi:

int_fast8_t, int_fast16_t, int_fast32_t, int_fast64_t, uint_fast8_t, uint_fast16_t,uint_fast32_t ,uint_fast64_t

Tutti gli altri tipi di questo modulo sono facoltativi.


268) Il tipo designato non è garantito per essere il più veloce per tutti gli scopi; se l'implementazione non ha fondati motivi per scegliere un tipo piuttosto che un altro, sceglierà semplicemente un tipo intero che soddisfi i requisiti di firma e larghezza.


Ma non si afferma perché questi tipi di numeri interi "veloci" siano più veloci.

  • Perché questi tipi di numeri interi veloci sono più veloci degli altri tipi di numeri interi?

Ho taggato la domanda con C ++, perché i tipi interi veloci sono disponibili anche in C ++ 17 nel file header di cstdint. Sfortunatamente, in ISO / IEC 14882: 2017 (C ++ 17) non esiste una sezione del genere sulla loro spiegazione; Avevo implementato quella sezione altrimenti nel corpo della domanda.


Informazioni: in C, sono dichiarati nel file di intestazione di stdint.h.


24
Il punto chiave qui è che questi tipi interi non sono tipi separati, magicamente più veloci. Sono solo alias per qualunque tipo di normale esistente sia il più veloce su quella macchina per quell'operazione.
mtraceur,

3
Il compilatore emette codici operativi operativi della CPU per caricare, archiviare, mascherare e modificare posizioni di memoria e registri di dimensioni specifiche; questo è tutto ciò che la CPU vede. Il sistema operativo non ha nulla a che fare con esso. Sta facendo tutto il compilatore, esattamente come se avessi specificato tu stesso il dato dato. ( Suppongo che un compilatore sia autorizzato a elaborarlo internamente in modo diverso - forse più efficacemente, se possibile - rispetto a un utente digitato, a condizione che non ci siano differenze di comportamento visibili.)
Peter - Ripristina Monica

1
@ RobertS-ReinstateMonica Per essere precisi, questi "alias" sono solo typedefaffermazioni. In genere , quindi, viene eseguito a livello di libreria standard. Naturalmente, le mette C standard nessuna vera restrizione su quello che typedefper - così per esempio una tipica implementazione è quello di fare int_fast32_tun typedefdi intsu un sistema a 32 bit, ma un compilatore ipotetica potrebbe ad esempio attuare un __int_fasttipo intrinseco e la promessa di fare un po 'di fantasia ottimizzazioni per scegliere il tipo di macchina più veloce, caso per caso, per le variabili di quel tipo, e quindi la libreria potrebbe fare proprio typedefquesto.
mtraceur,

1
@ RobertS-ReinstateMonica Sì, vero. Ottieni i massimi programmi di prestazioni con flag di compilazione specifici dell'architettura che rendono il binario meno portatile.
Peter - Ripristina Monica il

1
@ RobertS-ReinstateMonica Sarà più efficiente sulla piattaforma è stato compilato per , non necessariamente su .
HABO

Risposte:


152

Immagina una CPU che esegue solo operazioni aritmetiche a 64 bit. Ora immagina come implementeresti un'aggiunta senza segno a 8 bit su tale CPU. Richiederebbe necessariamente più di un'operazione per ottenere il risultato giusto. Su tale CPU, le operazioni a 64 bit sono più veloci delle operazioni su altre larghezze intere. In questa situazione, tuttiXint_fastY_t potrebbe presumibilmente essere un alias del tipo a 64 bit.

Se una CPU supporta operazioni veloci per tipi interi stretti e quindi un tipo più ampio non è più veloce di uno più stretto, allora Xint_fastY_t non sarà un alias del tipo più ampio di quanto sia necessario per rappresentare tutti i bit Y.

Per curiosità, ho verificato le dimensioni di una particolare implementazione (GNU, Linux) su alcune architetture. Questi non sono gli stessi in tutte le implementazioni sulla stessa architettura:

┌────╥───────────────────────────────────────────────────────────┐
 Y     sizeof(Xint_fastY_t) * CHAR_BIT                         
    ╟────────┬─────┬───────┬─────┬────────┬──────┬────────┬─────┤
     x86-64  x86  ARM64  ARM  MIPS64  MIPS  MSP430  AVR 
╞════╬════════╪═════╪═══════╪═════╪════════╪══════╪════════╪═════╡
 8   8       8    8      32   8       8     16      8   
 16  64      32   64     32   64      32    16      16  
 32  64      32   64     32   64      32    32      32  
 64  64      64   64     64   64      64    64      64  
└────╨────────┴─────┴───────┴─────┴────────┴──────┴────────┴─────┘

Si noti che sebbene le operazioni sui tipi più grandi possano essere più veloci, tali tipi occupano anche più spazio nella cache e quindi il loro utilizzo non comporta necessariamente prestazioni migliori. Inoltre, non ci si può sempre fidare che l'implementazione abbia fatto la scelta giusta in primo luogo. Come sempre, la misurazione è necessaria per risultati ottimali.


Schermata della tabella, per gli utenti Android:

Schermata della tabella sopra

(Android non ha caratteri box-box nel carattere mono - ref )


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Samuel Liew

@RobertSsupportsMonicaCellio No. "Non è uguale per tutte le architetture" è anche vero, ma è immediatamente evidente dai dati mostrati, quindi non riterrei necessario dichiarare l'ovvio. Ho mostrato solo i valori di una implementazione, e in effetti altri avranno scelte diverse. Controlla ad esempio x86-64 su Windows. Troverai dimensioni diverse rispetto a quanto mostrato qui.
Eerorika,

@RobertSsupportsMonicaCellio A mio avviso, questi commenti sono rilevanti per la risposta e appropriati qui. Lascerei che un moderatore li sposti, se sentono il bisogno di farlo.
Eerorika,

11

Non lo sono, almeno non in modo affidabile.

I tipi veloci sono semplicemente typedef per tipi normali, tuttavia spetta all'implementazione come definirli. Devono avere almeno la dimensione richiesta, ma possono essere più grandi.

È vero che su alcune architetture alcuni tipi interi hanno prestazioni migliori di altri. Ad esempio, ARM precoce implementazioni avevano istruzioni di accesso alla memoria per parole a 32 bit e per byte senza segno, ma non avevano istruzioni per mezze parole o byte con segno. Le istruzioni per la mezza parola e per il segno con segno sono state aggiunte in seguito, ma hanno ancora opzioni di indirizzamento meno flessibili, perché dovevano essere messe con le scarpe nello spazio di codifica di riserva. Inoltre, tutte le istruzioni di elaborazione dei dati effettive su ARM funzionano sulle parole, quindi in alcuni casi potrebbe essere necessario mascherare valori più piccoli dopo il calcolo per ottenere risultati corretti.

Tuttavia, esiste anche la preoccupazione concorrente della pressione della cache, anche se sono necessarie più istruzioni per caricare / archiviare / elaborare un valore inferiore. Il valore più piccolo potrebbe comunque funzionare meglio se riduce il numero di errori nella cache.

Le definizioni dei tipi su molte piattaforme comuni non sembrano essere state studiate. In particolare, le moderne piattaforme a 64 bit tendono ad avere un buon supporto per numeri interi a 32 bit, ma i tipi "veloci" sono spesso inutilmente a 64 bit su queste piattaforme.

Inoltre, i tipi in C diventano parte dell'ABI della piattaforma. Quindi, anche se un fornitore di piattaforme scopre di aver fatto delle scelte stupide, è difficile cambiare quelle stupide in seguito.

Ignora i tipi "veloci". Se sei davvero preoccupato per le prestazioni dei numeri interi, confronta il tuo codice con tutte le dimensioni disponibili.


7

I tipi veloci non sono più veloci di tutti gli altri tipi interi - in realtà sono identici a un tipo intero "normale" (sono solo un alias per quel tipo) - qualunque tipo sia il più veloce per contenere un valore di almeno così tanti bit.

Dipende solo dalla piattaforma per quale tipo intero ogni tipo veloce è un alias per.

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.