Esecuzione aritmetica in virgola fissa
Aritmetica in virgola fissa
Addizione e sottrazione
Ogni volta che si sommano due numeri a virgola fissa, potrebbe essere necessario un bit di riporto per rappresentare correttamente il risultato. Per questo motivo, quando si sommano due numeri B-bit (con lo stesso ridimensionamento), il valore risultante ha un bit in più rispetto ai due operandi utilizzati.
a = fi(0.234375,0,4,6); c = a+a
c = 0.4688 DataTypeMode: Fixed-point: binary point scaling Signedness: Unsigned WordLength: 5 FractionLength: 6
a.bin
ans = 1111
c.bin
ans = 11110
Se si sommano o si sottraggono due numeri con precisione diversa, è necessario prima allineare il punto radice per eseguire l’operazione. Il risultato è che sarà presente una differenza di più di un bit tra il risultato dell’operazione e gli operandi.
a = fi(pi,1,16,13); b = fi(0.1,1,12,14); c = a + b
c = 3.2416 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 18 FractionLength: 14
Moltiplicazione
In generale, un prodotto di massima precisione richiede una lunghezza della parola uguale alla somma delle lunghezze delle parole degli operandi. Nell’esempio seguente, si noti che la lunghezza della parola del prodotto c
è uguale alla lunghezza della parola di a
più la lunghezza della parola di b
. La lunghezza della frazione di c
è anche uguale alla lunghezza della frazione di a
più la lunghezza della frazione di b
.
a = fi(pi,1,20), b = fi(exp(1),1,16)
a = 3.1416 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 20 FractionLength: 17 b = 2.7183 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 13
c = a*b
c = 8.5397 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 36 FractionLength: 30
Matematica con altri tipi di dati integrati
Si noti che in C, il risultato di un’operazione tra un tipo di dati intero e un tipo di dati doppio viene promosso a doppio. Tuttavia, in MATLAB®, il risultato di un’operazione tra un tipo di dati intero integrato e un tipo di dati doppio è un numero intero. A questo proposito, l’oggetto fi
si comporta come i tipi di dati interi integrati in MATLAB.
Quando si esegue un’addizione tra fi
e double
, il doppio viene convertito in un fi
con lo stesso tipo numerico del fi
di input. Il risultato dell’operazione è un fi
. Quando si esegue una moltiplicazione tra fi
e double
, il doppio viene convertito in un fi
con la stessa lunghezza della parola e la stessa firma del fi
e la lunghezza della frazione di miglior precisione. Il risultato dell’operazione è un fi
.
a = fi(pi);
a = 3.1416 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 13
b = 0.5 * a
b = 1.5708 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 32 FractionLength: 28
Quando si esegue l’aritmetica tra fi
e uno dei tipi di dati integrati [u]int[8, 16, 32]
, la lunghezza della parola e la firma dell’intero vengono preservate. Il risultato dell’operazione è un fi
.
a = fi(pi); b = int8(2) * a
b = 6.2832 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 24 FractionLength: 13
Quando si esegue l’aritmetica tra fi
e un tipo di dati logico, il logico viene trattato come un oggetto fi
senza firma, con un valore di 0 o 1, e lunghezza della parola 1. Il risultato dell’operazione è un oggetto fi
.
a = fi(pi); b = logical(1); c = a*b
c = 3.1416 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 17 FractionLength: 13
L’oggetto fimath
Le proprietà fimath
definiscono le regole per l’esecuzione delle operazioni aritmetiche sugli oggetti fi
, incluso matematica, arrotondamento e proprietà dell’overflow. Un oggetto fi
può avere un oggetto fimath
locale, o può utilizzare le proprietà predefinite fimath
. È possibile collegare un oggetto fimath
a un oggetto fi
utilizzando setfimath
. In alternativa, è possibile specificare le proprietà fimath
nel costruttore fi
al momento della creazione. Quando un oggetto fi
ha un fimath
locale, invece di utilizzare le impostazioni predefinite, la visualizzazione dell’oggetto fi
mostra le proprietà fimath
. In questo esempio, a
ha la proprietà ProductMode
specificata nel costruttore.
a = fi(5,1,16,4,'ProductMode','KeepMSB')
a = 5 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 16 FractionLength: 4 RoundingMethod: Nearest OverflowAction: Saturate ProductMode: KeepMSB ProductWordLength: 32 SumMode: FullPrecision
ProductMode
di a
è impostata su KeepMSB
mentre, le restanti proprietà fimath
utilizzano i valori predefiniti.Nota
Per ulteriori informazioni sull’oggetto fimath
, le sue proprietà e i relativi valori predefiniti, vedere fimath Object Properties.
Crescita di bit
La tabella seguente mostra la crescita degli oggetti fi
A
e B
, quando il loro SumMode
e le loro proprietà ProductMode
utilizzano il valore fimath
predefinito, FullPrecision
.
A | B | Somma = A+B | Prodotto = A*B | |
---|---|---|---|---|
Formato | fi(vA,s1,w1,f1) | fi(vB,s2,w2,f2) | — | — |
Firma | s1 | s2 | Ssum = (s1 ||s2 ) | Sproduct = (s1 ||s2 ) |
Bit interi | I1 = w1-f1-s1 | I2= w2-f2-s2 | Isum = max(w1-f1, w2-f2) + 1 - Ssum | Iproduct = (w1 + w2) - (f1 + f2) |
Bit frazionari | f1 | f2 | Fsum = max(f1, f2) | Fproduct = f1 + f2 |
Bit totali | w1 | w2 | Ssum + Isum + Fsum | w1 + w2 |
Questo esempio mostra come la crescita di bit possa verificarsi in un for
-loop.
T.acc = fi([],1,32,0); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); for n = 1:length(x) acc = acc + x(n) end
acc = 1 s33,0 acc = 3 s34,0 acc = 6 s35,0
acc
aumenta ad ogni iterazione del loop. Questo aumento comporta due problemi: uno è che tale generazione di codice non consente di modificare i tipi di dati in un loop; l’altro è che se il loop è abbastanza lungo, si esaurisce la memoria in MATLAB. Vedere Controllo della crescita di bit per informazioni su alcune strategie atte ad evitare questo problema.Controllo della crescita di bit
Uso di fimath
Specificando le proprietà fimath
di un oggetto fi
, è possibile controllare la crescita di bit mentre le operazioni vengono eseguite sull’oggetto.
F = fimath('SumMode', 'SpecifyPrecision', 'SumWordLength', 8,... 'SumFractionLength', 0); a = fi(8,1,8,0, F); b = fi(3, 1, 8, 0); c = a+b
c = 11 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 8 FractionLength: 0 RoundingMethod: Nearest OverflowAction: Saturate ProductMode: FullPrecision SumMode: SpecifyPrecision SumWordLength: 8 SumFractionLength: 0 CastBeforeSum: true
L’oggetto fi
a
ha un oggetto fimath
locale F
. F
specifica la lunghezza della parola e la lunghezza della frazione della somma. Utilizzando le impostazioni predefinite fimath
, l’output c
ha normalmente una lunghezza della parola 9 e una lunghezza della frazione 0. Tuttavia, poiché a
aveva un oggetto fimath
locale, l’oggetto fi
risultante ha lunghezza della parola 8 e lunghezza della frazione 0.
In un for
-loop, è inoltre possibile utilizzare le proprietà fimath
per controllare la crescita di bit.
F = fimath('SumMode', 'SpecifyPrecision','SumWordLength',32,... 'SumFractionLength',0); T.acc = fi([],1,32,0,F); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); for n = 1:length(x) acc = acc + x(n) end
acc = 1 s32,0 acc = 3 s32,0 acc = 6 s32,0
A differenza di quando T.acc
utilizzava le proprietà fimath
predefinite, la crescita di bit acc
ora è limitata. Quindi, la lunghezza della parola di acc
rimane a 32.
Assegnazione con pedice
Un altro modo per controllare la crescita di bit consiste nell’utilizzare l’assegnazione con pedice. a(I) = b
assegna i valori di b
agli elementi di a
specificati dal vettore pedice I
, mentre mantiene il numerictype
di a
.
T.acc = fi([],1,32,0); T.x = fi([],1,16,0); x = cast(1:3,'like',T.x); acc = zeros(1,1,'like',T.acc); % Assign in to acc without changing its type for n = 1:length(x) acc(:) = acc + x(n) end
acc (:) = acc + x(n) indica che i valori al vettore pedice (:)
cambiano. Tuttavia, il numerictype
di output acc
rimane invariato. Poiché acc
è uno scalare, si otterrà lo stesso output se si utilizza (1)
come vettore pedice.
for n = 1:numel(x) acc(1) = acc + x(n); end
acc = 1 s32,0 acc = 3 s32,0 acc = 6 s32,0
Il numerictype
di acc
rimane invariato ad ogni iterazione del for
-loop.
L’assegnazione con pedice consente inoltre di controllare la crescita di bit in una funzione. Nella funzione cumulative_sum
, il numerictype
di y
non cambia, ma cambiano i valori negli elementi specificati da n.
function y = cumulative_sum(x) % CUMULATIVE_SUM Cumulative sum of elements of a vector. % % For vectors, Y = cumulative_sum(X) is a vector containing the % cumulative sum of the elements of X. The type of Y is the type of X. y = zeros(size(x),'like',x); y(1) = x(1); for n = 2:length(x) y(n) = y(n-1) + x(n); end end
y = cumulative_sum(fi([1:10],1,8,0))
y = 1 3 6 10 15 21 28 36 45 55 DataTypeMode: Fixed-point: binary point scaling Signedness: Signed WordLength: 8 FractionLength: 0
Nota
Per ulteriori informazioni sull’assegnazione con pedice, vedere la funzione subsasgn
.
accumpos
e accumneg
Un altro modo per controllare la crescita di bit consiste nell’utilizzare le funzioni accumpos
e accumneg
per eseguire operazioni di addizione e sottrazione. Simile all’utilizzo dell’assegnazione con pedice, accumpos
e accumneg
preserva il tipo di dati di uno degli oggetti fi
di input, consentendo di specificare un metodo di arrotondamento e un'azione di overflow sui valori di input.
Per ulteriori informazioni su come implementare accumpos
e accumneg
, vedere Avoid Multiword Operations in Generated Code
Overflow e arrotondamento
Quando si esegue l'aritmetica a virgola fissa, è necessario considerare la possibilità e le conseguenze dell'overflow. L’oggetto fimath
specifica le modalità di overflow e di arrotondamento utilizzate durante l’esecuzione di operazioni aritmetiche.
Overflow
Gli overflow possono verificarsi quando il risultato di un'operazione supera il valore massimo o minimo rappresentabile. L’oggetto fimath
ha una proprietà OverflowAction
che offre due metodi per gestire gli overflow: la saturazione e l’avvolgimento. Se si imposta OverflowAction
su saturate
, gli overflow vengono saturati al valore massimo o minimo nell’intervallo. Se si imposta OverflowAction
su wrap
, qualsiasi overflow viene avvolto utilizzando l’aritmetica modulo se non è presente la firma, o utilizzando l’avvolgimento in complemento a due se è presente la firma.
Per ulteriori informazioni su come rilevare l’overflow, vedere Underflow and Overflow Logging Using fipref.
Arrotondamento
È necessario considerare diversi fattori quando si sceglie un metodo di arrotondamento, inclusi il costo, la distorsione e se esiste o meno la possibilità di overflow. Il software Fixed-Point Designer™ offre diverse funzioni di arrotondamento per soddisfare i requisiti di qualsiasi progetto.
Metodo di arrotondamento | Descrizione | Costo | Distorsione | Possibilità di overflow |
---|---|---|---|---|
ceil | Arrotonda al numero rappresentabile più vicino nella direzione dell'infinito positivo. | Basso | Grande positiva | Sì |
convergent | Arrotonda al numero rappresentabile più vicino. In caso di parità, convergent arrotonda al numero pari più vicino. Questo approccio è il metodo di arrotondamento con meno distorsione fornito dal toolbox. | Alto | Senza distorsione | Sì |
floor | Arrotonda al numero rappresentabile più vicino nella direzione dell'infinito negativo, equivalente al troncamento del complemento a due. | Basso | Grande negativa | No |
nearest | Arrotonda al numero rappresentabile più vicino. In caso di parità, nearest arrotonda al numero rappresentabile più vicino nella direzione dell’infinito positivo. Questo metodo di arrotondamento è l’impostazione predefinita per la creazione di oggetti fi e fi aritmetici. | Medio | Piccola positiva | Sì |
round | Arrotonda al numero rappresentabile più vicino. In caso di parità, il metodo round arrotonda come segue:
| Alto |
| Sì |
fix | Arrotonda al numero rappresentabile più vicino nella direzione dello zero. | Basso |
| No |