Main Content

La traduction de cette page n'est pas à jour. Cliquez ici pour voir la dernière version en anglais.

Opérations en arithmétique à virgule fixe

Arithmétique à virgule fixe

Addition et soustraction

Chaque fois que vous additionnez deux nombres à virgule fixe, il est possible que vous ayez besoin d’un bit de report pour représenter correctement le résultat. Pour cette raison, lors de l’addition de deux nombres à B bits (avec la même mise à l’échelle), la valeur résultante possède un bit supplémentaire par rapport aux deux opérandes utilisés.

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

Si vous additionnez ou soustrayez deux nombres d’une précision différente, il faut d’abord aligner la séparation fractionnaire pour pouvoir effectuer l’opération. Le résultat est qu’il y a une différence de plus d’un bit entre le résultat de l’opération et les opérandes.

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

Multiplication

Généralement un produit en précision totale nécessite une longueur de mot égale à la somme des longueurs de mot des opérandes. Dans l’exemple suivant, notez que la longueur de mot du produit c est égale à la longueur de mot de a plus la longueur de mot de b. La longueur de la partie fractionnaire de c est aussi égale à la longueur de la partie fractionnaire de a plus la longueur de la partie fractionnaire de 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

Maths avec d’autres types de données prédéfinis

Notez qu'en C, le résultat d’une opération entre un type de données entier et un type de données double donne un double. Cependant, dans MATLAB®, le résultat d’une opération entre un type de données entier prédéfini et un type de données double est un entier. À cet égard, l’objet fi se comporte comme les types de données entiers prédéfinis dans MATLAB.

Lors de l’addition entre fi et double, le double est converti (par cast) en un fi ayant la même propriété numerictype que l’entrée fi. Le résultat de l’opération est un fi. Lors de la multiplication entre un fi et un double, le double est converti (par cast) en un fi ayant la même longueur de mot et le même signe que le fi, et une longueur de la partie fractionnaire avec la meilleure précision. Le résultat de l’opération est 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

Lors d’opérations arithmétiques entre un fi et l’un des types de données entiers prédéfinis, [u]int[8, 16, 32], la longueur du mot et le signe de l’entier sont préservés. Le résultat de l’opération est un fi.

a = fi(pi);
b = int8(2) * a
b = 

    6.2832

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 24
        FractionLength: 13

Lors d’opérations arithmétiques entre un fi et un type de données logique, le type logique est traité comme un objet fi non signé avec une valeur de 0 ou 1, et une longueur de mot de 1. Le résultat de l’opération est un objet 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’objet fimath

Les propriétés de fimath définissent les règles pour effectuer des opérations arithmétiques sur les objets fi, y compris les propriétés mathématiques, d'arrondi et d'overflow. Un objet fi peut avoir un objet fimath local, ou utiliser les propriétés fimath par défaut. Vous pouvez attacher un objet fimath à un objet fi en utilisant setfimath. Sinon, vous pouvez spécifier les propriétés fimath dans le constructeur fi lors de la création. Lorsqu’un objet fi a un fimath local, plutôt que d’utiliser les propriétés par défaut, l’affichage de l’objet fi montre les propriétés fimath. Dans cet exemple, a a la propriété ProductMode spécifiée dans le constructeur.

 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 propriété ProductMode de a est fixée à KeepMSB tandis que les propriétés fimath restantes utilisent les valeurs par défaut.

Remarque

Pour plus d’informations sur l’objet fimath, ses propriétés et leurs valeurs par défaut, voir fimath Object Properties.

Croissance des bits

Le tableau suivant montre la croissance des bits des objets fi, A et B, lorsque leurs propriétés SumMode et ProductMode utilisent la valeur fimath par défaut, FullPrecision.

 ABSomme = A+BProduit = A*B
Formatfi(vA,s1,w1,f1)fi(vB,s2,w2,f2)
Signes1s2Ssum = (s1||s2)Sproduct = (s1||s2)
Bits pour la partie entièreI1 = w1-f1-s1I2= w2-f2-s2Isum = max(w1-f1, w2-f2) + 1 - SsumIproduct = (w1 + w2) - (f1 + f2)
Bits de la partie fractionnairef1f2Fsum = max(f1, f2) Fproduct = f1 + f2
Total des bitsw1w2Ssum + Isum + Fsumw1 + w2

Cet exemple montre comment la croissance des bits peut survenir dans une boucle for.

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 longueur de mot de acc augmente à chaque itération de la boucle. Cette augmentation cause deux problèmes : D’une part, la génération de code ne permet pas de modifier le type de données dans une boucle. D’autre part, si la boucle est assez longue, vous vous retrouvez à court de mémoire dans MATLAB. Dans Contrôle de la croissance des bits, vous trouverez différentes stratégies pour éviter ce problème.

Contrôle de la croissance des bits

Utilisation de fimath

En spécifiant les propriétés fimath d’un objet fi, vous pouvez contrôler la croissance des bits à mesure que les opérations sont effectuées sur l’objet.

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’objet fi nommé a a un objet fimath local F. F spécifie la longueur de mot et la longueur de la partie fractionnaire de la somme. Dans le cadre des paramètres fimath par défaut, la sortie, c, a normalement une longueur de mot de 9 et une longueur de partie fractionnaire de 0. Cependant, comme a avait un objet fimath local, l’objet fi résultant a une longueur de mot de 8 et une longueur de partie fractionnaire de 0.

Vous pouvez également utiliser les propriétés fimath pour contrôler la croissance des bits dans une boucle for.

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

Contrairement à ce qui se passait quand T.acc utilisait les propriétés fimath par défaut, maintenant, la croissance des bits de acc est restreinte. Ainsi, la longueur de mot de acc reste égale à 32.

Affectation indicée

Une autre manière de contrôler la croissance des bits consiste à utiliser une affectation indicée. a(I) = b affecte les valeurs de b dans les éléments de a spécifiés par le vecteur d’indice, I, tout en retenant le numerictype de 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) impose que les valeurs au vecteur d’indice, (:), changent. Toutefois, la propriété numerictype de la sortie acc reste inchangée. Puisque acc est un scalaire, vous obtenez également la même sortie si vous utilisez (1) comme vecteur d’indice.

  for n = 1:numel(x)
    acc(1) = acc + x(n);
  end
acc = 

     1
      s32,0

acc = 

     3
      s32,0

acc = 

     6
      s32,0

Le numerictype de acc reste le même à chaque itération de la boucle for.

L’affectation indicée peut également vous aider à contrôler la croissance des bits dans une fonction. Dans la fonction cumulative_sum, la propriété numerictype de y ne change pas, mais les valeurs dans les éléments spécifiés par n changent.

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

Pour plus d’informations sur l’affectation indicée, voir la fonction subsasgn.

accumpos et accumneg

Une autre manière de contrôler la croissance des bits consiste à utiliser les fonctions accumpos et accumneg pour effectuer les opérations d’addition et de soustraction. Comme lorsqu’on utilise l'affectation indicée, accumpos et accumneg préservent le type de données de l’un de ses objets fi d’entrée tout en vous permettant de spécifier une méthode d’arrondi, et l’action pour l'overflow sur les valeurs d’entrée.

Pour plus d’informations sur la manière d’implémenter accumpos et accumneg, voir Avoid Multiword Operations in Generated Code

Overflows et arrondis

Lorsque vous effectuez des opérations en arithmétique à virgule fixe, pensez à la possibilité et aux conséquences des overflows. L’objet fimath spécifie les modes d'overflow et d’arrondi utilisés lors des opérations arithmétiques.

Overflows

Des overflows peuvent se produire lorsque le résultat d’une opération dépasse la valeur représentable maximale ou minimale. L’objet fimath a une propriété OverflowAction qui offre deux manières de gérer les overflows : la saturation et le wrap. Si l’on règle OverflowAction sur saturate, les overflows sont saturés à la valeur maximale ou minimale de la plage. Si l’on règle OverflowAction sur wrap, tous les overflows vont réaliser un « wrap » en utilisant l’arithmétique modulaire si les nombres sont non signés, ou le wrap en complément à deux, si les nombres sont signés.

Pour plus d’informations sur la manière de détecter un overflow, voir Underflow and Overflow Logging Using fipref.

Arrondis

Plusieurs facteurs interviennent lors du choix d’une méthode d’arrondi, notamment le prix, le biais, et le fait qu’il y ait ou non une possibilité d'overflow. Le software Fixed-Point Designer™ offre plusieurs fonctions d’arrondi pour répondre aux exigences de votre design.

Méthode d’arrondi DescriptionCoûtBiaisPossibilité d'overflow
ceil Arrondit au nombre représentable le plus proche dans la direction de l’infini positif.FaibleFortement positifOui
convergentArrondit au nombre représentable le plus proche. Dans le cas d’une égalité de distance du nombre représentable le plus proche, convergent arrondit au nombre pair le plus proche. Cette approche est la méthode d’arrondi la moins biaisée de la toolbox.ÉlevéNon biaiséeOui
floorArrondit au nombre représentable le plus proche dans la direction de l’infini négatif, équivalent à la troncature en complément à deux.FaibleFortement négatifNon
nearestArrondit au nombre représentable le plus proche. Dans le cas d’une égalité de distance du nombre représentable le plus proche, nearest arrondit au nombre représentable le plus proche dans la direction de l’infini positif. Cette méthode d’arrondi est la méthode par défaut pour la création d’objets fi et l’arithmétique fi.ModéréFaiblement positifOui
roundArrondit au nombre représentable le plus proche. Dans le cas d’une égalité de distance du nombre représentable le plus proche, la méthode round arrondit :
  • Les nombres positifs au nombre représentable le plus proche dans la direction de l’infini positif.

  • Les nombres négatifs au nombre représentable le plus proche dans la direction de l’infini négatif.

Élevé
  • Faiblement négatif pour les échantillons négatifs

  • Non biaisée pour les échantillons avec des valeurs positives et négatives également distribuées

  • Faiblement positif pour les échantillons positifs

Oui
fixArrondit au nombre représentable le plus proche dans la direction de zéro.Faible
  • Fortement positif pour les échantillons négatifs

  • Non biaisée pour les échantillons avec des valeurs positives et négatives également distribuées

  • Fortement négatif pour les échantillons positifs

Non