Opérateurs arithmétiques (référence C#)

Les opérateurs suivants effectuent des opérations arithmétiques avec des opérandes de types numériques :

Ces opérateurs sont pris en charge par tous les types numériques intégraux et à virgule flottante.

Dans le cas des types intégraux, ces opérateurs (à l’exception des opérateurs ++ et -- ) sont définis pour les types int, uint, long et ulong. Lorsque les opérandes sont d’autres types intégraux (sbyte, byte, short, ushort ou char), leurs valeurs sont converties en valeurs de type int, qui est également le type de résultat d’une opération. Lorsque des opérandes sont de types intégraux ou à virgule flottante différents, leurs valeurs sont converties en type contenant le plus proche, s’il existe un tel type. Pour plus d’informations, consultez la section Promotions numériques de la spécification du langage C#. Les opérateurs ++ et -- sont définis pour tous les types numériques intégraux et à virgule flottante, ainsi que pour le type char . Le type de résultat d’une expression d’affectation composée est le type de l’opérande de gauche.

Opérateur d’incrémentation ++

L’opérateur d’incrémentation unaire ++ incrémente son opérande de 1. L’opérande doit être une variable, un accès propriété ou un accès indexeur.

L’opérateur d’incrémentation est pris en charge sous deux formes : l’opérateur d’incrémentation suffixé, x++, et l’opérateur d’incrémentation préfixé, ++x.

Opérateur d'incrément suffixé

Le résultat de x++ est la valeur de xavant l’opération, comme le montre l’exemple suivant :

int i = 3;
Console.WriteLine(i);   // output: 3
Console.WriteLine(i++); // output: 3
Console.WriteLine(i);   // output: 4

Opérateur d'incrémentation préfixé

Le résultat de ++x est la valeur de xaprès l’opération, comme le montre l’exemple suivant :

double a = 1.5;
Console.WriteLine(a);   // output: 1.5
Console.WriteLine(++a); // output: 2.5
Console.WriteLine(a);   // output: 2.5

Opérateur de décrémentation --

L’opérateur de décrémentation unaire -- décrémente son opérande de 1. L’opérande doit être une variable, un accès propriété ou un accès indexeur.

L’opérateur de décrémentation est pris en charge sous deux formes : l’opérateur de décrémentation suffixé, x--, et l’opérateur de décrémentation préfixé, --x.

Opérateur de décrémentation suffixé

Le résultat de x-- est la valeur de xavant l’opération, comme le montre l’exemple suivant :

int i = 3;
Console.WriteLine(i);   // output: 3
Console.WriteLine(i--); // output: 3
Console.WriteLine(i);   // output: 2

Opérateur de décrémentation préfixé

Le résultat de --x est la valeur de xaprès l’opération, comme le montre l’exemple suivant :

double a = 1.5;
Console.WriteLine(a);   // output: 1.5
Console.WriteLine(--a); // output: 0.5
Console.WriteLine(a);   // output: 0.5

Opérateurs plus et moins unaires

L’opérateur unaire + retourne la valeur de son opérande. L’opérateur unaire - calcule la négation numérique de son opérande.

Console.WriteLine(+4);     // output: 4

Console.WriteLine(-4);     // output: -4
Console.WriteLine(-(-4));  // output: 4

uint a = 5;
var b = -a;
Console.WriteLine(b);            // output: -5
Console.WriteLine(b.GetType());  // output: System.Int64

Console.WriteLine(-double.NaN);  // output: NaN

Le type ulong ne prend pas en charge l’opérateur unaire -.

Opérateur de multiplication *

L’opérateur de multiplication * calcule le produit de ses opérandes :

Console.WriteLine(5 * 2);         // output: 10
Console.WriteLine(0.5 * 2.5);     // output: 1.25
Console.WriteLine(0.1m * 23.4m);  // output: 2.34

L’opérateur unaire * est l’opérateur d’indirection de pointeur.

Opérateur de division /

L’opérateur de division / divise son opérande de partie gauche par son opérande de partie droite.

Division d'entier

Pour les opérandes des types entiers, le résultat de l’opérateur / est de type entier et égal au quotient de deux opérandes arrondis vers le zéro :

Console.WriteLine(13 / 5);    // output: 2
Console.WriteLine(-13 / 5);   // output: -2
Console.WriteLine(13 / -5);   // output: -2
Console.WriteLine(-13 / -5);  // output: 2

Pour obtenir le quotient de deux opérandes comme un nombre à virgule flottante, utilisez le type float, double ou decimal :

Console.WriteLine(13 / 5.0);       // output: 2.6

int a = 13;
int b = 5;
Console.WriteLine((double)a / b);  // output: 2.6

Division à virgule flottante

Pour les types float, double et decimal, le résultat de l’opérateur / est le quotient de deux opérandes :

Console.WriteLine(16.8f / 4.1f);   // output: 4.097561
Console.WriteLine(16.8d / 4.1d);   // output: 4.09756097560976
Console.WriteLine(16.8m / 4.1m);   // output: 4.0975609756097560975609756098

Si l’un des opérandes est decimal, un autre opérande ne peut être float ni double, car ni float ni double ne sont implicitement convertibles en decimal. Vous devez convertir explicitement l’opérande float ou double en type decimal. Pour plus d’informations sur les conversions entre des types numériques, consultez Conversions numériques intégrées.

Opérateur de reste %

L’opérateur restant % calcule le reste après la division de son opérande de partie gauche par son opérande de partie droite.

Reste entier

Pour les opérandes des types entiers, le résultat de a % b est la valeur produite par a - (a / b) * b. Le signe du reste non zéro est le même que celui du signe de l’opérande de partie gauche, comme l’indique l’exemple suivant :

Console.WriteLine(5 % 4);   // output: 1
Console.WriteLine(5 % -4);  // output: 1
Console.WriteLine(-5 % 4);  // output: -1
Console.WriteLine(-5 % -4); // output: -1

Utilisez la méthode Math.DivRem pour calculer à la fois la division entière et les résultats du reste.

Reste à virgule flottante

En ce qui concerne les opérandes float et double, le résultat de x % y pour le x et le y finis est la valeur z afin que

  • Le signe de z, s’il est différent de zéro, soit identique au signe de x.
  • La valeur absolue de z soit la valeur produite par |x| - n * |y|, où n représente le plus grand entier possible inférieur ou égal à |x| / |y|, et où |x| et |y| sont les valeurs absolues de x et y, respectivement.

Notes

Cette méthode de calcul du reste est analogue à celle utilisée pour les opérandes entiers. Toutefois, elle ne suit pas la spécification IEEE 754. Si l’opération de reste doit être conforme à la spécification IEEE 754, utilisez la méthode Math.IEEERemainder.

Pour plus d’informations sur le comportement de l’opérateur % avec des opérandes non finis, consultez la section Opérateur de reste dans la Spécification du langage C#.

Pour les opérandes decimal, l’opérateur de reste % équivaut à l’opérateur de reste de type System.Decimal.

L’exemple suivant illustre le comportement de l’opérateur de reste pour les opérandes à virgule flottante :

Console.WriteLine(-5.2f % 2.0f); // output: -1.2
Console.WriteLine(5.9 % 3.1);    // output: 2.8
Console.WriteLine(5.9m % 3.1m);  // output: 2.8

Opérateur d’addition +

L’opérateur d’addition + calcule la somme de ses opérandes :

Console.WriteLine(5 + 4);       // output: 9
Console.WriteLine(5 + 4.3);     // output: 9.3
Console.WriteLine(5.1m + 4.2m); // output: 9.3

Vous pouvez également utiliser l’opérateur + pour la concaténation de chaînes et la combinaison de délégués. Pour plus d’informations, consultez l’article + et +=, opérateurs.

Opérateur de soustraction -

L’opérateur de soustraction - soustrait son opérande de partie droite de son opérande de partie gauche :

Console.WriteLine(47 - 3);      // output: 44
Console.WriteLine(5 - 4.3);     // output: 0.7
Console.WriteLine(7.5m - 2.3m); // output: 5.2

Vous pouvez également utiliser l’opérateur - pour la suppression de délégués. Pour plus d’informations, consultez l’article - et -=, opérateurs.

Assignation composée

Pour un opérateur binaire op, une expression d’assignation composée du formulaire

x op= y

équivaut à :

x = x op y

sauf que x n’est évalué qu’une seule fois.

L’exemple suivant illustre l’utilisation de l’assignation composée avec des opérateurs arithmétiques :

int a = 5;
a += 9;
Console.WriteLine(a);  // output: 14

a -= 4;
Console.WriteLine(a);  // output: 10

a *= 2;
Console.WriteLine(a);  // output: 20

a /= 4;
Console.WriteLine(a);  // output: 5

a %= 3;
Console.WriteLine(a);  // output: 2

En raison des promotions numériques, le résultat de l’opération op risque de ne pas être implicitement convertible en type T de x. Dans ce cas, si op est un opérateur prédéfini et que le résultat de l’opération est explicitement convertible en type T de x, une expression d’assignation composée de la forme x op= y équivaut à x = (T)(x op y), sauf que x n’est évalué qu’une seule fois. L’exemple suivant illustre ce comportement :

byte a = 200;
byte b = 100;

var c = a + b;
Console.WriteLine(c.GetType());  // output: System.Int32
Console.WriteLine(c);  // output: 300

a += b;
Console.WriteLine(a);  // output: 44

Dans l’exemple précédent, la valeur 44 est le résultat de la conversion de la valeur 300 en type byte.

Notes

Dans le contexte de vérification de dépassement de capacité vérifié, l’exemple précédent lève un OverflowException. Pour plus d’informations, consultez la section Dépassement arithmétique entier.

Vous utilisez également les opérateurs += et -= pour vous abonner d’un événements puis vous désabonner, respectivement. Pour plus d’informations, consultez Guide pratique pour s’abonner et annuler l’abonnement à des événements.

Priorité des opérateurs et associativité

La liste suivante présente les opérateurs arithmétiques de la priorité la plus élevée à la plus basse :

  • Opérateurs suffixés d’incrémentation x++ et de décrémentation x--
  • Opérateurs préfixés d’incrémentation ++x et de décrémentation --x et opérateurs unaires + et -
  • Opérateurs multiplicatifs *, / et %
  • Opérateurs additifs + et -

Les opérateurs arithmétiques binaires sont associatifs sur leur gauche. Autrement dit, les opérateurs de même niveau de priorité sont évalués de gauche à droite.

Utilisez des parenthèses, (), pour modifier l’ordre d’évaluation imposé par la priorité et l’associativité de l’opérateur.

Console.WriteLine(2 + 2 * 2);   // output: 6
Console.WriteLine((2 + 2) * 2); // output: 8

Console.WriteLine(9 / 5 / 2);   // output: 0
Console.WriteLine(9 / (5 / 2)); // output: 4

Pour obtenir la liste complète des opérateurs C# classés par niveau de priorité, consultez la section Priorité des opérateurs de l’article Opérateurs C#.

Débordement arithmétique et division par zéro

Quand le résultat d’une opération arithmétique n’est pas compris dans la plage de valeurs finies possibles du type numérique impliqué, le comportement d’un opérateur arithmétique varie selon le type de ses opérandes.

Débordement arithmétique entier

La division d'un entier par zéro lève toujours une exception DivideByZeroException.

Si un dépassement arithmétique entier se produit, un contexte de vérification de débordement, qui peut être vérifié ou non vérifié, contrôle le comportement qui en résulte :

  • Dans un contexte vérifié, si le débordement se produit dans une expression constante, une erreur de compilation se produit. Sinon, un OverflowException est levé quand l’opération est effectuée au moment de l’exécution.
  • Dans un contexte non vérifié, le résultat est tronqué en supprimant tous les bits de poids fort qui ne tiennent pas dans le type destinataire.

Avec les instructions vérifiées et non vérifiées, vous pouvez utiliser les opérateurs checked et unchecked pour contrôler le contexte de vérification de dépassement, dans lequel une expression est évaluée :

int a = int.MaxValue;
int b = 3;

Console.WriteLine(unchecked(a + b));  // output: -2147483646
try
{
    int d = checked(a + b);
}
catch(OverflowException)
{
    Console.WriteLine($"Overflow occurred when adding {a} to {b}.");
}

Par défaut, les opérations arithmétiques se produisent dans un contexte unchecked.

Débordement arithmétique à virgule flottante

Les opérations arithmétiques avec les types float et double ne lèvent jamais d’exceptions. Le résultat des opérations arithmétiques avec ces types peut être une des valeurs spéciales qui représentent l’infini et non un nombre :

double a = 1.0 / 0.0;
Console.WriteLine(a);                    // output: Infinity
Console.WriteLine(double.IsInfinity(a)); // output: True

Console.WriteLine(double.MaxValue + double.MaxValue); // output: Infinity

double b = 0.0 / 0.0;
Console.WriteLine(b);                // output: NaN
Console.WriteLine(double.IsNaN(b));  // output: True

Pour les opérandes du type decimal, le dépassement arithmétique lève toujours un OverflowException. La division d'un nombre par zéro lève toujours une exception DivideByZeroException.

Erreurs d’arrondi

En raison des limitations générales de la représentation à virgule flottante des nombres réels et de l’arithmétique à virgule flottante, des erreurs d’arrondi peuvent se produire dans les calculs avec les types à virgule flottante. Autrement dit, le résultat d’une expression peut différer du résultat mathématique attendu. L’exemple suivant illustre plusieurs cas de ce genre :

Console.WriteLine(.41f % .2f); // output: 0.00999999

double a = 0.1;
double b = 3 * a;
Console.WriteLine(b == 0.3);   // output: False
Console.WriteLine(b - 0.3);    // output: 5.55111512312578E-17

decimal c = 1 / 3.0m;
decimal d = 3 * c;
Console.WriteLine(d == 1.0m);  // output: False
Console.WriteLine(d);          // output: 0.9999999999999999999999999999

Pour plus d’informations, consultez les remarques dans les pages de référence System.Double, System.Single ou System.Decimal.

Capacité de surcharge de l’opérateur

Un type défini par l’utilisateur peut surcharger les opérateurs arithmétiques unaires (++, --, + et -) et binaires (*, /, %, + et -). Quand un opérateur binaire est surchargé, l’opérateur d’assignation composée correspondant est aussi implicitement surchargé. Un type défini par l’utilisateur ne peut pas surcharger explicitement un opérateur d’assignation composée.

Opérateurs vérifiés définis par l’utilisateur

À compter de C# 11, lorsque vous surchargez un opérateur arithmétique, vous pouvez utiliser le mot clé checked pour définir la version vérifiée de cet opérateur. L’exemple suivant montre comment effectuer cette opération :

public record struct Point(int X, int Y)
{
    public static Point operator checked +(Point left, Point right)
    {
        checked
        {
            return new Point(left.X + right.X, left.Y + right.Y);
        }
    }
    
    public static Point operator +(Point left, Point right)
    {
        return new Point(left.X + right.X, left.Y + right.Y);
    }
}

Lorsque vous définissez un opérateur vérifié, vous devez également définir l’opérateur correspondant sans le modificateur checked. L’opérateur vérifié est appelé dans un contexte vérifié; l’opérateur sans le checkedmodificateur est appelé dans un contexte non vérifié. Si vous fournissez uniquement l’opérateur sans le modificateur checked, il est appelé à la fois dans un contexte checked et unchecked.

Lorsque vous définissez les deux versions d’un opérateur, il est attendu que leur comportement diffère uniquement lorsque le résultat d’une opération est trop grand pour être représenté dans le type de résultat comme suit :

  • Un opérateur vérifié lève une OverflowException.
  • Un opérateur sans modificateur checked retourne une instance représentant un résultat tronqué.

Pour plus d’informations sur la différence de comportement des opérateurs arithmétiques intégrés, consultez la section Dépassement arithmétique et division par zéro.

Vous pouvez utiliser le modificateur checked uniquement lorsque vous surchargez l’un des opérateurs suivants :

Notes

Le contexte de contrôle de dépassement dans le corps d’un opérateur vérifié n’est pas affecté par la présence du modificateur checked. Le contexte par défaut est défini par la valeur de l’option de compilateur CheckForOverflowUnderflow. Utilisez les instructions uncheckedet checked pour spécifier explicitement le contexte de vérification de dépassement de capacité, comme le montre l’exemple au début de cette section.

spécification du langage C#

Pour plus d’informations, consultez les sections suivantes de la spécification du langage C# :

Voir aussi