Perché la divisione hardware impiega molto più tempo della moltiplicazione?


37

Perché la divisione hardware impiega molto più tempo della moltiplicazione su un microcontrollore? Ad esempio, su un dsPIC, una divisione richiede 19 cicli, mentre la moltiplicazione richiede solo un ciclo di clock.

Ho seguito alcuni tutorial, tra cui l' algoritmo di divisione e l' algoritmo di moltiplicazione su Wikipedia. Ecco il mio ragionamento.

Un algoritmo di divisione, come un metodo di divisione lenta con ripristino su Wikipedia, è un algoritmo ricorsivo. Ciò significa che i risultati (intermedi) del passaggio kvengono utilizzati come input per il passaggio k+1, il che significa che questi algoritmi non possono essere parallelizzati. Pertanto, ci vogliono almeno ncicli per completare la divisione, mentre nè un numero di bit in un dividendo. Per i dividendi a 16 bit, ciò equivale ad almeno 16 cicli.

Un algoritmo di moltiplicazione non deve essere ricorsivo, il che significa che è possibile parallelizzarlo. Tuttavia, ci sono molti algoritmi di moltiplicazione diversi, e non ho idea di quale possa essere utilizzato dai microcontrollori. Come funziona la moltiplicazione su un hardware / microcontrollore?

Ho trovato un algoritmo moltiplicatore Dadda , che dovrebbe richiedere solo un ciclo di clock per finire. Tuttavia, ciò che non ottengo qui è che l'algoritmo di Dadda procede in tre passaggi, mentre i risultati del passaggio 1 vengono utilizzati nel passaggio 2, ecc. In base a ciò, occorrerebbero almeno tre cicli di clock per terminare.


2
L'algoritmo non sta davvero definendo il numero di cicli di clock. La tua specifica CPU potrebbe avere un moltiplicatore / divisore hardware funzionante in un ciclo o 20 cicli indipendentemente dall'implementazione interna.
Eugene Sh.

1
OP, puoi fornire un link che fornisca maggiori informazioni sui cicli 19 vs 1 di cui parli? Qualcosa di specifico sul tuo DSP.
Vladimir Cravero,

1
Grazie per le risposte Ecco una scheda tecnica per il mio microcontrollore: ww1.microchip.com/downloads/en/DeviceDoc/70005127c.pdf . Vedere Panoramica del set di istruzioni, a partire da pagina 292. Indica che tutte le istruzioni DIV richiedono 18 cicli, mentre tutte le istruzioni MUL richiedono solo 1 ciclo. Ma non è comune solo per questo MCU, l'ho visto in molti altri MCU.
Marko Gulin,

2
@Curd, beh, sono quasi uguali, no? Sono per me Non penso che lo illustri bene come potresti immaginare.
TonyM,

1
L'altro fattore è l'economia e i modelli di utilizzo. La maggior parte degli usi invoca si moltiplica molto più spesso della divisione. Dedicare una vasta area di silicio a una funzione di divisione dell'hardware più rapida che verrà utilizzata relativamente di rado è una cattiva economia. Meglio creare un chip più piccolo ed economico, o usare la logica extra in un modo più produttivo. A proposito, quando ho iniziato con i minicomputer, dividere non era sempre un'istruzione. Su alcune macchine era una chiamata alla libreria del software, come la radice quadrata.
nigel222,

Risposte:


34

Un divisore mappa molto meno elegantemente con l'hardware tipico. Prendi come esempio gli FPGA ICE40 di Lattice.

Confrontiamo due casi: questo moltiplicatore da 8x8 bit a 16 bit:

module multiply (clk, a, b, result);
   input clk;
   input [7:0]a;
   input [7:0]b;
   output [15:0]result;
   always @(posedge clk)
     result = a * b;
endmodule // multiply

e questo divisore che riduce gli operandi di 8 e 8 bit al risultato di 8 bit:

module divide(clk, a, b, result);
   input clk;
   input [7:0] a;
   input [7:0] b;
   output [7:0] result;
   always @(posedge clk)
     result = a / b;
endmodule // divide

(Sì, lo so, l'orologio non fa nulla)

Una panoramica dello schema generato durante la mappatura del moltiplicatore su un FPGA ICE40 è disponibile qui e il divisore qui .

Le statistiche di sintesi di Yosys sono:

moltiplicare

  • Numero di fili: 155
  • Numero di punte: 214
  • Numero di cavi pubblici: 4
  • Numero di bit di filo pubblico: 33
  • Numero di memorie: 0
  • Numero di bit di memoria: 0
  • Numero di processi: 0
  • Numero di celle: 191
    • SB_CARRY 10
    • SB_DFF 16
    • SB_LUT4 165

dividere

  • Numero di fili: 145
  • Numero di punte: 320
  • Numero di cavi pubblici: 4
  • Numero di bit di filo pubblico: 25
  • Numero di memorie: 0
  • Numero di bit di memoria: 0
  • Numero di processi: 0
  • Numero di celle: 219
    • SB_CARRY 85
    • SB_DFF 8
    • SB_LUT4 126

Vale la pena notare che le dimensioni della verilog generata per un moltiplicatore a larghezza intera e un divisore che divide al massimo non sono così estreme. Tuttavia, se guarderai le immagini qui sotto, noterai che il moltiplicatore ha forse una profondità di 15, mentre il divisore sembra più o meno 50; il percorso critico (ovvero il percorso più lungo che può verificarsi durante il funzionamento) è ciò che definisce la velocità!


Non sarai in grado di leggere questo, comunque, per avere un'impressione visiva. Penso che sia possibile individuare le differenze di complessità. Questi sono moltiplicatori / divisori a ciclo singolo!

Moltiplicare

Moltiplicare su un ICE40 (avviso: immagine ~ 100 Mpixel)

Immagine in scala del moltiplicatore

Dividere

( Dividi su un ICE40 ) (avviso: immagine ~ 100 Mpixel)

Immagine in scala del divisore


4
no, puoi implementarli in modo non iterativo. Ma ci vorrà solo un po 'di tempo prima che il risultato valido si "incresphi" attraverso la logica. Le implementazioni di cui sopra sono non iterative.
Marcus Müller,

9
Voglio un poster murale del divisore.
Ian Howson,

5
C'è un PDF ora nel moltiplicano Gist. È 3378 × 3177 mm, quindi ti preghiamo di discutere con l'altro significativo prima di metterlo sul soffitto della camera da letto.
Marcus Müller,

2
Le tue immagini da 100 megapixel sono impressionanti, ma sono eccessive per il punto che stai cercando di fare e causano enormi problemi a chiunque cerchi di visualizzare questa pagina su un dispositivo con memoria limitata come un telefono o un tablet. Se si desidera visualizzare le immagini in linea, trovare un modo per produrre un'anteprima a risoluzione inferiore.
Dave Tweed

4
Yo, quei grafici graphviz sono fuori di testa, yo!
Spencer Williams,

8

La divisione lenta è intrinsecamente iterativa, quindi tende a richiedere più tempo. Esistono algoritmi di divisione lenta leggermente più veloci di quelli semplici, usando le tabelle di ricerca. L'algoritmo SRT produce due bit per ciclo. Un errore in tale tabella fu la causa del famigerato bug Pentium FDIV (circa 1994). Quindi ci sono i cosiddetti algoritmi di divisione rapida.

Naturalmente, in linea di principio, è possibile semplicemente utilizzare un'enorme tabella di ricerca per calcolare il prodotto o il quoziente di due numeri e quindi ottenere risultati in un singolo ciclo, ma ciò tende a diventare rapidamente poco pratico all'aumentare del numero di bit per numero.


Ma la linea di fondo è: gli algoritmi di divisione non possono essere parallelizzati, a differenza degli algoritmi di moltiplicazione, ed è per questo che sono molto più lenti?
Marko Gulin,

2
@MarkoGulin "Impossibile" è un'affermazione molto forte. Non è certo semplice.
Spehro Pefhany,

2
Penso che potresti indebolirlo da "gli algoritmi di divisione non possono essere parallelizzati" a "i modi in cui abbiamo scoperto di parallelizzare la divisione sono più tesi sull'hardware che implementa la divisione che sulla moltiplicazione parallela". Sphero fornisce un esempio di come eseguire la divisione a ciclo singolo usando le porte O (2 ^ n) per moltiplicare i numeri n-bit ... ma non è pratico.
Cort Ammon,

1
La divisione lunga può sfruttare il parallelismo a qualsiasi livello desiderato calcolando un reciproco approssimativo che, moltiplicato per il divisore, produce un risultato della forma 1000 ... xxxx, quando si lavora con un divisore in tale forma con N leadig zero, è facile per calcolare N bit del risultato con ogni passaggio.
supercat

8

Possiamo avere più livelli di logica per ciclo di clock, ma esiste un limite, esattamente quanti strati di logica possiamo avere e quanto complessi possano essere questi livelli dipenderà dalla nostra velocità di clock e dal nostro processo a semiconduttore.

Tuttavia, ci sono molti algoritmi di moltiplicazione diversi e non ho idea di quale possa essere utilizzato dai microcontrollori

Afaict la maggior parte della moltiplicazione nei computer utilizza una variante della moltiplicazione binaria lunga. La moltiplicazione binaria lunga comporta

  • Spostamento di un operando di vari importi diversi
  • Mascherare i numeri spostati in base al secondo operando
  • Sommando i risultati del mascheramento.

Quindi diamo un'occhiata all'implementazione dell'hardware.

  • Lo spostamento è solo una questione di come colleghiamo le cose, quindi viene gratis.
  • Il mascheramento richiede AND gate. Ciò significa uno strato di logica, quindi dal punto di vista temporale è economico.
  • L'aggiunta è relativamente costosa a causa della necessità di una catena di trasporto. Fortunatamente c'è un trucco che possiamo usare. Per la maggior parte delle fasi di aggiunta anziché aggiungere due numeri per produrne uno, possiamo aggiungere tre numeri per produrne due.

Quindi lasciamo ballpark di quanti stadi logici abbiamo bisogno per un moltiplicatore 8x8 con risultati a 16 bit. Per semplicità supponiamo che non cerchiamo di ottimizzare per il fatto che non tutti i risultati intermedi hanno bit in tutte le posizioni.

Supponiamo che un sommatore completo sia implementato in due "stadi gate".

  • 1 per il mascheramento per produrre 8 risultati intermedi.
  • 2 per aggiungere gruppi di tre numeri per ridurre gli 8 risultati intermedi a 6
  • 2 per aggiungere gruppi di tre numeri per ridurre a 6 i risultati intermedi 6
  • 2 per aggiungere un gruppo di tre numeri per ridurre i 4 risultati intermedi a 3
  • 2 per aggiungere un gruppo di tre numeri per ridurre i 3 risultati intermedi a 2
  • 32 per sommare i due risultati finali.

Quindi circa 46 stadi logici totali. La maggior parte dei quali viene spesa sommando gli ultimi due risultati intermedi.

Questo potrebbe essere ulteriormente migliorato sfruttando il fatto che non tutti i risultati intermedi hanno tutti i bit presenti (questo è fondamentalmente ciò che fa il moltiplicatore dada), usando un sommatore lookahead carry per il passaggio finale. Aggiungendo 7 numeri per produrre 3 anziché tre per produrre due (riducendo il numero di stadi al prezzo di più cancelli e cancelli più larghi) ecc.

Questi sono tutti dettagli minori, il punto importante è che il numero di stadi necessari per moltiplicare due numeri di n bit e produrre un risultato di 2n bit è approssimativamente proporzionale a n.


D'altra parte, se guardiamo agli algoritmi di divisione, scopriamo che tutti hanno un processo iterativo in cui.

  1. Ciò che viene fatto su una iterazione dipende fortemente dai risultati della precedente iterazione.
  2. il numero di stadi logici necessari per implementare un'iterazione è approssimativamente proporzionale a n (sottrazione e confronto sono molto simili nella complessità all'aggiunta)
  3. anche il numero di iterazioni è approssimativamente proporzionale a n.

Quindi il numero di stadi logici richiesti per implementare la divisione è approssimativamente proporzionale a n quadrato.


La ringrazio per la risposta. Ho letto su Wiki che l'algoritmo di Dadda è molto efficiente quando si tratta del numero richiesto di porte per implementare questo algoritmo sull'hardware. Nonostante ciò, la maggior parte dell'hardware utilizza la "moltiplicazione binaria lunga"?
Marko Gulin,

1
Penso che l'algotihm di Dada sia una versione ottimizzata della moltiplicazione binaria lunga.
Peter Green,

Brucio 8 cicli per fare una divisione 1 / x. Quindi lo uso contro una moltiplicazione di 8 cicli per un costo fisso di 16 cicli.
b degnan,

Ciò dimostra bene che la moltiplicazione non è poi tanto peggio dell'aggiunta dopo tutto.
Hagen von Eitzen,

1
Un'iterazione richiede una sottrazione che può essere eseguita negli stadi O (lgN) usando l'hardware O (NlgN) o gli stadi O (sqrt (N)) usando l'hardware O (N). Il punto essenziale, tuttavia, è che la moltiplicazione richiede fasi O (lgN), mentre la divisione richiede fasi O (NlgN). Non O (N * N) ma maggiore della moltiplicazione per un fattore di O (N) a meno che non si inizi prendendo un reciproco approssimativo in modo da consentire più lavoro da fare per passo.
supercat

4

Un algoritmo di divisione (in realtà qualsiasi algoritmo) può essere creato in un ciclo di clock. Se sei disposto a pagare per i transistor extra e la frequenza di clock inferiore consentita.

Supponiamo di avere una serie di gate che implementa un ciclo di clock di un algoritmo di divisione multi-ciclo esistente. Per rendere l'algoritmo a ciclo singolo, utilizzare più fasi dell'hardware (simile a quello utilizzato in una fase dell'algoritmo a più cicli), con l'uscita di una fase che alimenta la fase successiva.

Ovviamente la ragione per non farlo in questo modo è che usa molti transistor. Ad esempio per una divisione a 16 bit può utilizzare quasi 16 X più transistor. Anche avere più stadi di gate abbassa la frequenza di clock massima consentita (perché ci sono più stadi di ritardo di propagazione).


4

Gli algoritmi di divisione pratica sono tutti basati su suite numeriche che convergono al quoziente.

  • Esistono metodi additivi, come non ripristinanti o SRT, che funzionano aggiungendo o rimuovendo 2 ^ N al quoziente e aggiungendo o rimuovendo il Divisore 2 ^ N al resto parziale fino a quando non converge a zero.

  • Esistono metodi moltiplicativi, come Newton-Raphson o Goldshmidth, che sono metodi di ricerca delle radici in cui la divisione viene calcolata come l'inverso della moltiplicazione.

I metodi additivi danno uno o pochi bit per ciclo. I metodi moltiplicativi raddoppiano il numero di bit per ciascun ciclo, ma necessitano di un'approssimazione iniziale, spesso ottenuta con una tabella costante.

Le denominazioni "lente" e "veloci" sono fuorvianti, poiché la velocità effettiva dipende dal numero di bit, dalla quantità di hardware dedicata alla funzione (e un moltiplicatore veloce è molto grande) ...

La divisione è più lenta della moltiplicazione perché non esiste un metodo diretto e parallelo per calcolarla: o esiste un'iterazione o l'hardware viene copiato per implementare l'iterazione come blocchi in cascata (o pipeline).


0

Perché la divisione hardware impiega molto più tempo della moltiplicazione su un microcontrollore?

Questa non è una domanda di elettronica. Nella migliore delle ipotesi è una domanda da computer, meglio indirizzata allo StackTranslate.it.

Vedi, per esempio, qui: la moltiplicazione è più veloce della divisione float?

In realtà, è una domanda di vita reale: perché la divisione impiega molto più tempo della moltiplicazione?

Quale preferiresti calcolare su carta?

51 * 82

o

4182 / 51

La divisione richiede più tempo della moltiplicazione perché è più difficile da fare .

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.