DOMANDA Numero primo

  • Autore discussione Autore discussione MPG
  • Data d'inizio Data d'inizio
Pubblicità
Se non ricordo male,
le operazioni sui bit vengono eseguite più velocemente dalla CPU rispetto alle operazioni aritmetiche (naturalmente bisogna sapere cosa si sta facendo altrimenti si possono commettere errori, anche inavvertitamente).
Per quanto riguarda la parola chiave register, si tratta di un "suggerimento" del programmatore che raccomanda al compilatore di conservare una variabile all'interno dei registri della CPU in quanto verrà continuamente usata, evitando così di prelevarne continuamente il contenuto dalla RAM (o dalle cache) e velocizzando così l'esecuzione del codice. Tuttavia impostare a register una variabile non implica che il compilatore la terrà veramente costantemente in un registro interno anzi, la maggior parte dei compilatori moderni in qualche modo "ignora tale raccomandazione, perché riescono a determinare automaticamente cosa è meglio tenere nei registri. Ad ogni modo dipende dal particolare compilatore e dalla sua versione.
 
Ultima modifica:
Figurati. ;)

!(n & 1) è uguale a (n % 2 == 0)

questo perchè avviene l'AND sul primo bit usando come maschera 1. L'and restituisce 1 solo se entrambi i bit sono ad 1, ed il bit meno significativo (quello più a destra) di un numero ti permette di capire se è pari o dispari (1 = dispari, 0 = pari).

Quindi ad esempio:

2 & 1 = 0010 & 0001 = 0
3 & 1 = 0011 & 0001 = 1

Usando poi ! verifichi se è falso (se l'and torna 0 allora eseguendo ! ottieni 1, quindi il numero è pari).
A basso livello il tutto è tradotto come:

Codice:
MOV EAX,DWORD PTR SS:[ARG.1]
AND EAX,00000001
JNZ SHORT 011371B3

(sieve & 1) equivale a (sieve % 2 != 0) o anche (sieve % 2)

Stesso discorso fatto sopra, esegue l'AND sul primo bit e se torna 1, allora il numero è dispari.

C'è qualche vantaggio prestazionale nelle forme a sinistra rispetto a quelle a destra?
Non ho capito invece perché usi lo specificatore di classe di memoria register (cioè, immagino che sia per dire al compilatore di mettere la variabile in un registro anziché in ram), ma mi sfugge l'utilità. Inoltre mi piacerebbe sapere perché su alcuni libri dicono che è deprecato.

Si, il vantaggio prestazionale c'è. Come dice giustamente BAT, le istruzioni bit a bit sono più rapide. Sulle CPU moderne certi vantaggi sono quasi trascurabili; certo è che mettendo assieme tutto, qualche differenza c'è. ;)

Per quanto riguarda register: in effetti il compilatore sa meglio del programmatore cosa fare, quindi se non la si usa va bene (e forse anche meglio). Poi i compilatori moderni ottimizzano molto bene, specie se si utilizza anche un flag come -O2.

Non è proprio inerente alla discussione, ma in questo articolo Articolo Switch mostro anche la differenza tra una compilazione con flag ed una senza su switch (e nella prima parte if, ma la seconda penso sia più interessante :) ).

Infine: i registri della CPU godono di ottime prestazioni in quanto parte della CPU (anche se piccole memorie); l'accesso in RAM richiede più tempo per leggere il dato (oltre ad un minimo di overhead dovuto alla lettura e "causato" dalla traduzione dell'indirizzo da virtuale a fisico, specie se non mappato nel TLB); chi ha programmato in asm e chi lo usa per divertimento tende infatti a sfruttare al massimo i registri (che non bastano mai).


Ps. ho scritto un pò di fretta, ma non dovrei aver commesso errori/sviste.
 
Infine: i registri della CPU godono di ottime prestazioni in quanto parte della CPU (anche se piccole memorie); l'accesso in RAM richiede più tempo per leggere il dato (oltre ad un minimo di overhead dovuto alla lettura e "causato" dalla traduzione dell'indirizzo da virtuale a fisico, specie se non mappato nel TLB); chi ha programmato in asm e chi lo usa per divertimento tende infatti a sfruttare al massimo i registri (che non bastano mai).
@DispatchCode lo so, sono uno studente di informatica e proprio un anno fa passavo le mie giornate a studiare architettura degli elaboratori e sistemi operativi, materia molto interessante (e che in questi giorni torna utile sapere, visto che si parla ovunque di branch prediction ed esecuzione speculativa!). Purtroppo non conosco l'assembly x86 (mi sono esercitato un pochino con il "finto" linguaggio della integer java virtual machine descritto sul Tanenbaum) e non ho tempo per studiarlo, anche se mi piacerebbe. Grazie ancora per la spiegazione.
Ora sto andando off-topic e me ne scuso (magari se lo ritengono opportuno i moderatori possono spostare questa parte del messaggio) ma mi piacerebbe sapere che ne pensi in merito a una questione: voglio assemblare un computer per programmare su windows e linux, e non so che processore prendere vista la faccenda di meltdown, per quanto riguarda intel, e del problema dei segfault che pare affliggere molti ryzen (so che per l'uso normale non succede niente ma per compilare potrebbe essere un problema) e in generale la situazione di confusione attuale. Mi piacerebbe avere l'opinione di un programmatore, anche da un punto di vista squisitamente (micro)architetturale.

P.S: lungi da me voler sembrare saccente, ma il tuo codice compilato con gcc 4.9.3 (in MinGW) mi dice che 2 non è primo, sia con la funzione eratostene che isPrime, perché qui:
Codice:
    if(n == 1 || n == 0 || !(n & 1))
        return false;
    else if(n == 2)
        return true;

restituisce false per qualunque numero pari, compreso 2, quindi forse è meglio scambiare di posto le due condizioni:D. Inoltre ho dovuto aggiungere l'include del file d'intestazione string.h per la funzione memset, sennò non compilava.
 
Ultima modifica:
Ammetto di aver spostato l'ultima condizione quando ho incollato qui il codice, senza badare a ciò che stavo facendo; sul pc avevo quella condizione come ultimo else if. Quindi mea culpa.

Io ho compilato con cl.exe, non ricordo se avevo aggiunto cstring, ma quasi sicuramente si.

Ps. Riguardo ad asm, prima o poi lo affronterai anche in uni qualche esame che lo vede coinvolto.
 
L’uso della keyword “register” è ormai deprecato (e ignorato in C++, dove viene tenuta per compatibilità con il C). Ormai i compilatori sono bravi nel capire quali variabili debbano essere ottimizzate. Anche decenni fa l’uso del register aveva senso per architetture come la Motorola, che avevano parecchi registri di memoria, mentre era meglio lasciare perdere con gli Intel.
L’uso del register ha senso adesso nella programmazione embedded con piccoli compilatori, che ormai non usa più nessuno
 
in futuro mi sa di no, e finora l'ho affrontato solo sotto un aspetto teorico.
E per quanto riguarda l'off topic nello spoiler che avevo scritto?
Non saprei dirti quale CPU non ne sarà affetta. Ti conviene aspettare ancora un po', ci sono novità in uscita.
E non credo che tutti i "virus writers" riusciranno a sfruttare quelle falle, tenendo poi conto che per i maggiori OS esistono patch rilasciate dai produttori degli stessi.
 
Non saprei dirti quale CPU non ne sarà affetta. Ti conviene aspettare ancora un po', ci sono novità in uscita.
E non credo che tutti i "virus writers" riusciranno a sfruttare quelle falle, tenendo poi conto che per i maggiori OS esistono patch rilasciate dai produttori degli stessi.
Grazie e, se posso avere una tua opinione a prescindere da questa faccenda, da programmatore, quale consideri meglio come cpu (a proposito, non so che peso dare alla faccenda dei segfault di ryzen)?
 
Ho visto che ne stanno discutendo qui, anche se non ho seguito la discussione Bug CPU Intel

Non ho capito se ti stai riferendo a Intel vs. AMD, oppure ad un'architettura di Intel nello specifico. In entrambi i casi dipende dalle necessità e dalle occasioni. Personalmente ho sempre avuto entrambi, con una maggioranza lieve di Intel. Al momento sto utilizzando un notebook con un Intel i7 6700HQ, ma è stata un'occasione, altrimenti avrei puntato su un i5 (ha 2 anni il mio notebook).
Tanto poi si torna sempre lì: il "collo di bottiglia" alla fine è il disco.

Se vuoi proseguiamo in privato, altrimenti tra poco passerà un mod a tirarci le orecchie.
 
Pubblicità
Pubblicità
Indietro
Top