Re: AVR 8 bit: unsigned integer e FPU SW emulation
Inviato: 1 dic 2021, 2:12
Se vuoi moltiplicare a virgola fissa, e hai a disposizione al massimo interi a 32 bit (uint32_t), e la frequenza massima che vuoi ottenere è di 50 MHz (50.000.000 Hz)... non puoi moltiplicarla per numeri maggiori di 85, altrimenti hai un overflow (il risultato supererebbe ).
Quindi non puoi moltiplicare 50.000.000 per 1527 e poi dividere per 64.
Però, se ti basta una granularità di regolazione di 100 Hz, puoi moltiplicare 500.000 per 1527, dividere per 64 e moltiplicare per 100, o più in generale:
Però la frazione si discosta da per 65 parti per milione.
Una frazione che la approssima a meno di 0,1 parti per milione è :
La routine della divisione intera (al posto dello shift a destra di 6 bit) non è poi così terribile. Si può anche eseguire. La precisione ottenibile è circa pari a quella dei float (a 32 bit), che hanno 7 cifre significative.
L'operazione dovrebbe risultare più veloce, e il programma più snello al non includere le routine di calcolo dei float.
Volendo arrotondare il risultato della divisione all'intero più vicino, anziché troncarlo, raddoppiamo numeratore e denominatore (riusciamo ancora a stare dentro i 32 bit), e aggiungiamo 1 al numeratore:
Magari potresti provare a fare una simulazione esaustiva su PC su tutte le frequenze da 100 Hz a 50 MHz, a passi da 100 Hz, e vedere che differenze ti danno il calcolo con i double, i float e quello con la frazione. Probabilmente sotto i 10 MHz i calcoli coincidono sempre. Bisogna anche vedere che precisione serve. Se andiamo oltre la precisione del quarzo che ti genera il clock, dovrebbe bastare.
Non ci sono i double nel compilatore che usi? O gli interi a 64 bit?
C'è un altro modo per fare le moltiplicazioni, spezzando moltiplicando e moltiplicatore in "parte alta" e "parte bassa" ed eseguendo quattro moltiplicazioni e tre somme:
Mi pare che così si riesca ad avere il prodotto su un numero doppio di bit (64 anziché 32 per esempio), ma non ricordo bene il procedimento.
Quindi non puoi moltiplicare 50.000.000 per 1527 e poi dividere per 64.
Però, se ti basta una granularità di regolazione di 100 Hz, puoi moltiplicare 500.000 per 1527, dividere per 64 e moltiplicare per 100, o più in generale:
Però la frazione si discosta da per 65 parti per milione.
Una frazione che la approssima a meno di 0,1 parti per milione è :
La routine della divisione intera (al posto dello shift a destra di 6 bit) non è poi così terribile. Si può anche eseguire. La precisione ottenibile è circa pari a quella dei float (a 32 bit), che hanno 7 cifre significative.
L'operazione dovrebbe risultare più veloce, e il programma più snello al non includere le routine di calcolo dei float.
Volendo arrotondare il risultato della divisione all'intero più vicino, anziché troncarlo, raddoppiamo numeratore e denominatore (riusciamo ancora a stare dentro i 32 bit), e aggiungiamo 1 al numeratore:
Magari potresti provare a fare una simulazione esaustiva su PC su tutte le frequenze da 100 Hz a 50 MHz, a passi da 100 Hz, e vedere che differenze ti danno il calcolo con i double, i float e quello con la frazione. Probabilmente sotto i 10 MHz i calcoli coincidono sempre. Bisogna anche vedere che precisione serve. Se andiamo oltre la precisione del quarzo che ti genera il clock, dovrebbe bastare.
Non ci sono i double nel compilatore che usi? O gli interi a 64 bit?
C'è un altro modo per fare le moltiplicazioni, spezzando moltiplicando e moltiplicatore in "parte alta" e "parte bassa" ed eseguendo quattro moltiplicazioni e tre somme:
Mi pare che così si riesca ad avere il prodotto su un numero doppio di bit (64 anziché 32 per esempio), ma non ricordo bene il procedimento.