Compartilhar via


Operadores aritméticos (referência do C#)

Os seguintes operadores executam operações aritméticas com operandos de tipos numéricos:

Todos os tipos numéricos de ponto integral e flutuante dão suporte a esses operadores.

Os inttipos , uinte longulong definem todos esses operadores. Os outros tipos integrais (sbyte, byte, short, ushort e char) definem apenas os operadores ++ e --. Para os outros operadores, se você usar os tipos sbyteintegrais, byte, shortou ushortchar como operandos, os valores serão convertidos no int tipo e o tipo de resultado será int. Se os operandos forem diferentes tipos integrais ou de ponto flutuante, seus valores serão convertidos no tipo que contém mais próximo, se esse tipo existir. Para saber mais, confira a seção Promoções numéricas da Especificação da linguagem C#. Os operadores ++ e -- são definidos para todos os tipos numéricos de ponto integral e flutuante e para o tipo char. O tipo de resultado de uma expressão de atribuição composta é o tipo do operando à esquerda.

A linguagem C# faz referência a documentos da versão mais recentemente lançada da linguagem C#. Ele também contém a documentação inicial para funcionalidades em pré-visualizações públicas para o próximo lançamento do idioma.

A documentação identifica qualquer recurso introduzido pela primeira vez nas três últimas versões do idioma ou nas versões prévias públicas atuais.

Dica

Para descobrir quando um recurso foi introduzido pela primeira vez em C#, consulte o artigo sobre o histórico de versão da linguagem C#.

Operador de incremento ++

O operador de incremento unário ++ incrementa seu operando em 1. O operando precisa ser uma variável, um acesso de propriedade ou um acesso de indexador.

Há duas formas de suporte para o operador de incremento: o operador de incremento pós-fixado, x++, e o operador de incremento pré-fixado, ++x.

Operador de incremento pós-fixado

O resultado de x++ é o valor de xantes da operação, como mostra o exemplo a seguir:

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

Operador de incremento de prefixo

O resultado de ++x é o valor de xapós a operação, como mostra o exemplo a seguir:

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

Operador de decremento --

O operador de decremento unário -- decrementa o operando em 1. O operando precisa ser uma variável, um acesso de propriedade ou um acesso de indexador.

O operador de decremento está disponível em duas formas: o operador de decremento de postfixo x--e o operador de decremento de prefixo. --x

Operador de decremento pós-fixado

O resultado de x-- é o valor de xantes da operação, como mostra o exemplo a seguir:

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

Operador de decremento de prefixo

O resultado de --x é o valor de xapós a operação, como mostra o exemplo a seguir:

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

Operadores unários de adição e subtração

O operador unário + retorna o valor do operando. O operador unário - calcula a negação numérica do operando.

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

O tipo ulong não dá suporte ao operador unário -.

Operador de multiplicação *

O operador de multiplicação * calcula o produto dos operandos:

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

O operador unário * é o operador de indireção de ponteiro.

Operador de divisão /

O operador de divisão / divide o operando à esquerda pelo operando à direita.

Divisão de inteiros

Para os operandos de tipos inteiros, o resultado do / operador é de um tipo inteiro e é igual ao quociente dos dois operandos arredondados para zero:

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

Para obter o quociente dos dois operandos como um número de ponto flutuante, use o floattipo, doubleou decimal digite:

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

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

Divisão de ponto flutuante

Para o float, doublee decimal tipos, o / operador retorna o quociente dos dois operandos:

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

Se um operando for decimal, o outro operando não poderá ser float ou doubleporque nem tem floatdouble uma conversão implícita em decimal. Você deve converter explicitamente o operando float ou double para o tipo decimal. Para saber mais sobre as conversões entre tipos numéricos, confira a as Conversões numéricas internas.

Operador de resto %

O operador de resto % calcula o resto após dividir o operando à esquerda pelo à direita.

Resto inteiro

Para operandos de tipos inteiros, o resultado a % b é o valor produzido por $a - \frac{a}{b} \times b$. O sinal do restante diferente de zero corresponde ao sinal do operando à esquerda, como mostra o exemplo a seguir:

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

Use o método Math.DivRem para calcular a divisão de inteiros e os resultados do resto.

Resto de ponto flutuante

Para os operandos float e double, o resultado de x % y para o x e o y finitos é o valor z tal que

  • O sinal de z, se não zero, corresponder ao sinal de x.
  • O valor absoluto vem z do cálculo $|x| - n \times |y|$, onde n é o maior inteiro menor ou igual a $\frac{|x|}{|y|}$. Aqui, $|x|$ e $|y|$ representam os valores absolutos de x e y, respectivamente.

Observação

Esse método de computação do restante é semelhante ao método usado para operandos inteiros, mas é diferente da especificação IEEE 754. Se precisar que a operação de resto esteja em conformidade com a especificação IEEE 754, use o método Math.IEEERemainder.

Para saber mais sobre o comportamento do operador % com operandos não finitos, confira a seção Operador de restante da especificação da linguagem C#.

Para decimal operandos, o operador % restante funciona da mesma forma que o operador restante do System.Decimal tipo.

O exemplo a seguir demonstra como o operador restante se comporta com operandos de ponto flutuante:

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

Operador de adição +

O operador de adição + calcula a soma dos operandos:

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

Você também pode usar o operador + para a combinação de delegado e concatenação de cadeia de caracteres. Para obter mais informações, confira o artigo Operadores + e +=.

Operador de subtração -

O operador - de subtração subtrai o operando à direita do operando à esquerda:

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

Você também pode usar o - operador para remover um delegado. Para obter mais informações, consulte os operadores e -= os- operadores.

Atribuição composta

Para um operador binário op, uma expressão de atribuição composta do formato

x op= y

É equivalente a

x = x op y

Exceto que x é avaliado apenas uma vez.

O seguinte exemplo demonstra o uso da atribuição composta com operadores aritméticos:

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

Devido a promoções numéricas, o resultado da op operação pode não ser implicitamente conversível para o tipo T de x. Nesse caso, se op for um operador predefinido e o resultado da operação for explicitamente convertido no tipo T de x, uma expressão de atribuição composta da forma x op= y será equivalente a x = (T)(x op y), exceto que x será avaliada apenas uma vez. O exemplo a seguir demonstra esse comportamento:

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

No exemplo anterior, o valor 44 é o resultado da conversão do valor 300 para o tipo byte.

Observação

No contexto de verificação de estouro verificado, o exemplo anterior lança um OverflowException. Para obter mais informações, confira a seção Estouro aritmético inteiro.

Use também os operadores += e -= para assinar e cancelar a assinatura de eventos, respectivamente. Para obter mais informações, confira Como assinar e cancelar a assinatura de eventos.

Precedência e associatividade do operador

A lista a seguir ordena operadores aritméticos da precedência mais alta à menor precedência:

  • Incluir um pós-fixo a operadores de incremento x++ e decremento x--
  • Operadores de incremento e decremento de prefixo++x, unário + e - operadores --x
  • Operadores de multiplicação *, / e %
  • Operadores de adição + e -

Operadores aritméticos binários são associativos à esquerda. Ou seja, o compilador avalia operadores com o mesmo nível de precedência da esquerda para a direita.

Use parênteses, (), para alterar a ordem de avaliação imposta pela precedência e pela capacidade de associação do operador.

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

Para obter a lista completa de operadores C# ordenados por nível de precedência, consulte a seção Precedência de operador do artigo Operadores C#.

Estouro aritmético e divisão por zero

Quando o resultado de uma operação aritmética está fora do intervalo de valores finitos possíveis do tipo numérico envolvido, o comportamento de um operador aritmético depende do tipo dos operandos.

Estouro aritmético de inteiros

A divisão de inteiro por zero sempre lança um DivideByZeroException.

Se ocorrer um estouro aritmético inteiro, o contexto de verificação de estouro, que pode ser checked ou unchecked, controlará o comportamento resultante:

  • Em um contexto verificado, se o estouro acontece em uma expressão de constante, ocorre um erro em tempo de compilação. Caso contrário, quando a operação é executada em tempo de execução, uma OverflowException é gerada.
  • Em um contexto não verificado, o resultado é truncado pelo descarte dos bits de ordem superior que não se ajustam ao tipo de destino.

Observação

A divisão inteiro tem um caso especial em que um ArithmeticException pode ser lançado mesmo em um contexto desmarcado. Quando o operando à esquerda é o valor mínimo de um tipo inteiro com sinal (int.MinValue ou long.MinValue) e o operando à direita é -1, o resultado não pode ser representado no tipo de destino. O runtime do .NET gera um ArithmeticException neste caso, conforme mostrado no exemplo a seguir:

int a = int.MinValue;
int b = -1;
try
{
    int c = unchecked(a / b);
}
catch (ArithmeticException)
{
    Console.WriteLine($"Overflow occurred when dividing {a} by {b}.");
}

Juntamente com as instruções checked e unchecked, você pode usar os operadores checked e unchecked para controlar o contexto de verificação de estouro, no qual uma expressão é avaliada:

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}.");
}

Por padrão, as operações aritméticas ocorrem em um contexto não verificado.

Estouro aritmético de ponto flutuante

Operações aritméticas usando os float tipos e double nunca geram uma exceção. O resultado de operações aritméticas usando esses tipos pode ser um dos valores especiais que representam infinito e não um número:

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

Para os operandos do tipo decimal, o estouro aritmético sempre gera uma OverflowException. A divisão por zero sempre lança uma DivideByZeroException.

Erros de arredondamento

Devido a limitações gerais na representação de ponto flutuante de números reais e aritmética de ponto flutuante, erros de round-off podem ocorrer em cálculos que usam tipos de ponto flutuante. O resultado de uma expressão pode ser diferente do resultado matemático esperado. O seguinte exemplo demonstra vários casos desse tipo:

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

Para obter mais informações, consulte as observações nas páginas de referência System.Double, System.Single ou System.Decimal .

Capacidade de sobrecarga do operador

Você pode sobrecarregar os operadores aritméticos unários (++, --, +e -) e binários (*, /%, e +-) para um tipo definido pelo usuário. Ao sobrecarregar um operador binário, você também sobrecarrega implicitamente o operador de atribuição composta correspondente. A partir do C# 14, um tipo definido pelo usuário pode sobrecarregar explicitamente os operadores de atribuição composta (op=) para fornecer uma implementação mais eficiente. Normalmente, um tipo sobrecarrega esses operadores porque o valor pode ser atualizado no local, em vez de alocar uma nova instância para armazenar o resultado da operação. Se um tipo não fornecer uma sobrecarga explícita, o compilador gerará a sobrecarga implícita.

Operadores verificados definidos pelo usuário

Ao sobrecarregar um operador aritmético, você pode usar a checked palavra-chave para definir a versão verificada desse operador. O seguinte exemplo mostra como fazer isso:

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);
    }
}

Ao definir um operador verificado, você também deve definir o operador correspondente sem o modificador checked. Um contexto verificado chama o operador verificado e um contexto desmarcado chama o operador sem o checked modificador.

Quando você define ambas as versões de um operador, o comportamento deles é diferente somente quando o resultado de uma operação é muito grande para representar no tipo de resultado da seguinte maneira:

  • Um operador verificado lança um OverflowException.
  • Um operador sem o modificador checked retornará uma instância que representa um resultado truncado.

Para obter informações sobre a diferença no comportamento dos operadores aritméticos internos, consulte a seção Estouro aritmético e divisão por zero.

Você só poderá usar o checked modificador quando sobrecarregar qualquer um dos seguintes operadores:

Observação

O checked modificador não afeta o contexto de verificação de estouro dentro de seu corpo. O contexto padrão é definido pelo valor da opção do compilador CheckForOverflowUnderflow. Use as instruções checked e unchecked para especificar explicitamente o contexto de verificação de estouro, como demonstra o exemplo no início desta seção.

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Confira também