Main Content

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
La proprietà ProductMode di a è impostata su KeepMSB mentre, le restanti proprietà fimath utilizzano i valori predefiniti.

Remarque

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.

 ABSomma = A+BProdotto = A*B
Formatofi(vA,s1,w1,f1)fi(vB,s2,w2,f2)
Firmas1s2Ssum = (s1||s2)Sproduct = (s1||s2)
Bit interiI1 = w1-f1-s1I2= w2-f2-s2Isum = max(w1-f1, w2-f2) + 1 - SsumIproduct = (w1 + w2) - (f1 + f2)
Bit frazionarif1f2Fsum = max(f1, f2) Fproduct = f1 + f2
Bit totaliw1w2Ssum + Isum + Fsumw1 + 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
La lunghezza della parola 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 fimathlocale, 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

Remarque

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 DescrizioneCostoDistorsionePossibilità di overflow
ceil Arrotonda al numero rappresentabile più vicino nella direzione dell'infinito positivo.BassoGrande positiva
convergentArrotonda 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.AltoSenza distorsione
floorArrotonda al numero rappresentabile più vicino nella direzione dell'infinito negativo, equivalente al troncamento del complemento a due.BassoGrande negativaNo
nearestArrotonda 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.MedioPiccola positiva
roundArrotonda al numero rappresentabile più vicino. In caso di parità, il metodo round arrotonda come segue:
  • I numeri positivi sono arrotondati al numero rappresentabile più vicino nella direzione dell'infinito positivo.

  • I numeri negativi sono arrotondati al numero rappresentabile più vicino nella direzione dell'infinito negativo.

Alto
  • Piccola negativa per campioni negativi

  • Senza distorsione per campioni con valori positivi e negativi distribuiti uniformemente

  • Piccola positiva per campioni positivi

fixArrotonda al numero rappresentabile più vicino nella direzione dello zero.Basso
  • Grande positiva per campioni negativi

  • Senza distorsione per campioni con valori positivi e negativi distribuiti uniformemente

  • Grande negativa per campioni positivi

No