Operadores aritméticos (referencia de C#)

Los operadores siguientes realizan operaciones aritméticas con operandos de tipos numéricos:

Estos operadores se admiten en todos los tipos numéricos enteros y de punto flotante.

En el caso de tipos enteros, dichos operadores (excepto los operadores ++ y --) se definen para los tipos int, uint, long y ulong. Cuando los operandos son de otro tipo entero (sbyte, byte, short, ushort o char), sus valores se convierten en el tipo int, que también es el tipo de resultado de una operación. Cuando los operandos son de distintos tipos enteros o de punto flotante, sus valores se convierten al tipo contenedor más cercano, si ese tipo existe. Para obtener más información, vea la sección Promociones numéricas de Especificación del lenguaje C#. Los operadores ++ y -- se definen para todos los tipos numéricos enteros y de punto flotante y el tipo char. El tipo de resultado de una expresión de asignación compuesta es el tipo del operando izquierdo.

Operador de incremento ++

El operador de incremento unario ++ incrementa su operando en 1. El operando debe ser una variable, un acceso de propiedad o un acceso de indexador.

El operador de incremento se admite en dos formas: el operador de incremento posfijo (x++) y el operador de incremento prefijo (++x).

Operador de incremento de postfijo

El resultado de x++ es el valor de xantes de la operación, tal y como se muestra en el ejemplo siguiente:

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

Operador de incremento prefijo

El resultado de ++x es el valor de xdespués de la operación, tal y como se muestra en el ejemplo siguiente:

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 --

El operador de decremento unario -- disminuye su operando en 1. El operando debe ser una variable, un acceso de propiedad o un acceso de indexador.

El operador de decremento se admite en dos formas: el operador de decremento posfijo (x--) y el operador de decremento prefijo (--x).

Operador de decremento de postfijo

El resultado de x-- es el valor de xantes de la operación, como se muestra en el ejemplo siguiente:

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

Operador de decremento de prefijo

El resultado de --x es el valor de xdespués de la operación, tal y como se muestra en el ejemplo siguiente:

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

Operadores unarios más y menos

El operador + unario devuelve el valor de su operando. El operador unario - calcula la negación numérica del 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

El operador unario - no es compatible con el tipo ulong.

Operador de multiplicación *

El operador de multiplicación * calcula el producto de sus 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

El operador unario * es el operador de direccionamiento indirecto del puntero.

Operador de división /

El operador de división / divide el operando izquierdo entre el derecho.

División de enteros

Para los operandos de tipos enteros, el resultado del operador / es de un tipo entero y equivale al cociente de los dos operandos redondeados hacia cero:

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 obtener el cociente de los dos operandos como número de punto flotante, use el tipo float, double o decimal:

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

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

División de punto flotante

Para los tipos float, double y decimal, el resultado del operador / es el cociente de los dos 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

Si uno de los operandos es decimal, otro operando no puede ser float ni double, ya que ni float ni double se convierte de forma implícita a decimal. Debe convertir explícitamente el operando float o double al tipo decimal. Para obtener más información sobre las conversiones entre tipos numéricos, consulte Conversiones numéricas integradas.

Operador de resto %

El operador de resto % calcula el resto después de dividir el operando izquierdo entre el derecho.

Resto entero

En el caso de los operandos de tipos enteros, el resultado de a % b es el valor producido por a - (a / b) * b. El signo de resto distinto de cero es el mismo que el del operando izquierdo, como se muestra en el ejemplo siguiente:

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 el método Math.DivRem para calcular los resultados de la división de enteros y del resto.

Resto de punto flotante

En el caso de los operandos float y double, el resultado de x % y para x e y finitos es el valor z, de modo que

  • el signo de z, si no es cero, es el mismo que el signo de x;
  • el valor absoluto de z es el valor producido por |x| - n * |y|, donde n es el entero más grande posible que sea menor o igual que |x| / |y|, y |x| e |y| son los valores absolutos de x e y, respectivamente.

Nota:

Este método de cálculo del resto es análogo al que se usa para los operandos enteros, pero difiere de la especificación IEEE 754. Si necesita la operación de resto conforme con la especificación IEEE 754, use el método Math.IEEERemainder.

Para información sobre el comportamiento del operador % con operandos no finitos, vea la sección Operador de resto de la Especificación del lenguaje C#.

En el caso de los operandos decimal, el operador de resto % es equivalente al operador de resto del tipo System.Decimal.

En el ejemplo siguiente se muestra el comportamiento del operador de resto con operandos de punto flotante:

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 suma +

El operador de suma + calcula la suma de sus operandos:

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

También puede usar el operador + para la concatenación de cadenas y la combinación de delegados. Para obtener más información, consulte Operadores + y +=.

Operador de resta -

El operador de resta - resta el operando derecho del izquierdo:

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

También puede usar el operador - para la eliminación de delegados. Para obtener más información, consulte Operadores - y -=.

Asignación compuesta

Para un operador binario op, una expresión de asignación compuesta con el formato

x op= y

es equivalente a

x = x op y

salvo que x solo se evalúa una vez.

En el ejemplo siguiente se muestra el uso de la asignación compuesta con 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

A causa de las promociones numéricas, el resultado de la operación op podría no ser convertible de forma implícita en el tipo T de x. En tal caso, si op es un operador predefinido y el resultado de la operación es convertible de forma explícita en el tipo T de x, una expresión de asignación compuesta con el formato x op= y es equivalente a x = (T)(x op y), excepto que x solo se evalúa una vez. En el ejemplo siguiente se muestra ese comportamiento:

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

En el ejemplo anterior, el valor 44 es el resultado de convertir el valor 300 al tipo byte.

Nota

En un contexto de comprobación de desbordamiento de tipo checked, el ejemplo anterior produce una excepción OverflowException. Para obtener más información, consulte la sección Desbordamiento aritmético de enteros.

Los operadores += y -= también se usan para suscribirse y cancelar la suscripción a un evento, respectivamente. Para obtener más información, vea Procedimiento para suscribir y cancelar la suscripción a eventos.

Prioridad y asociatividad de los operadores

En la lista siguiente se ordenan los operadores aritméticos de la prioridad más alta a la más baja:

  • Operadores de incremento x++ y decremento x-- posfijos
  • Operadores de incremento ++x y decremento --x prefijos, y operadores unarios + y -.
  • Operadores de multiplicación *, / y %.
  • Operadores de suma adición + y -.

Los operadores aritméticos binarios son asociativos a la izquierda. Es decir, los operadores con el mismo nivel de prioridad se evalúan de izquierda a derecha.

Use los paréntesis, (), para cambiar el orden de evaluación impuesto por la prioridad y la asociatividad de operadores.

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 obtener la lista completa de los operadores de C# ordenados por nivel de prioridad, vea la sección Prioridad de operadores del artículo Operadores de C#.

Desbordamiento aritmético y división por cero

Si el resultado de una operación aritmética está fuera del intervalo de valores finitos posibles del tipo numérico implicado, el comportamiento de un operador aritmético depende del tipo de sus operandos.

Desbordamiento aritmético de enteros

La división de enteros por cero siempre produce una DivideByZeroException.

En el caso de desbordamiento aritmético de enteros, el comportamiento resultante lo controla el contexto de comprobación de desbordamiento, que puede ser comprobado o no comprobado:

  • En un contexto comprobado, si el desbordamiento se produce en una expresión constante, se produce un error de compilación. De lo contrario, si la operación se realiza en tiempo de ejecución, se inicia una excepción OverflowException.
  • En un contexto no comprobado, el resultado se trunca mediante el descarte de los bits de orden superior que no caben en el tipo de destino.

Junto con las instrucciones comprobadas y no comprobadas, puede usar los operadores checked y unchecked para controlar el contexto de comprobación de desbordamiento, en el que se evalúa una expresión:

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

De forma predeterminada, las operaciones aritméticas se producen en un contexto no comprobado.

Desbordamiento aritmético de punto flotante

Las operaciones aritméticas con los tipos float y double nunca inician una excepción. El resultado de las operaciones aritméticas con esos tipos puede ser uno de varios valores especiales que representan infinito y no un 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 los operandos del tipo decimal, el desbordamiento aritmético siempre inicia una excepción OverflowException. La división decimal por cero siempre produce una excepción DivideByZeroException.

Errores de redondeo

Debido a las limitaciones generales de la representación de punto flotante de los números reales y la aritmética de punto flotante, es posible que se produzcan errores de redondeo en los cálculos con tipos de punto flotante. Es decir, es posible que el resultado de una expresión difiera del resultado matemático esperado. En el ejemplo siguiente se muestran varios de estos casos:

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 más información, vea los comentarios en las páginas de referencia de System.Double, System.Single o System.Decimal.

Posibilidad de sobrecarga del operador

Un tipo definido por el usuario puede sobrecargar los operadores unarios (++, --, + y -), los operadores binarios (*, /, %, + y -) y los operadores aritméticos. Cuando se sobrecarga un operador binario, también se sobrecarga de forma implícita el operador de asignación compuesta correspondiente. Un tipo definido por el usuario no puede sobrecargar de forma explícita un operador de asignación compuesta.

Operadores comprobados definidos por el usuario

A partir de C# 11, al sobrecargar un operador aritmético, puede usar la palabra clave checked para definir la versión comprobada de ese operador. En el siguiente ejemplo se muestra cómo hacerlo:

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

Al definir un operador comprobado, también debe definir el operador correspondiente sin el modificador checked. Se llama al operador comprobado en un contexto comprobado; el operador sin el modificador checked se llama en un contexto no comprobado. Si solo proporciona el operador sin la palabra clave checked, se llama en un contexto checked y en un contexto unchecked.

Cuando se definen ambas versiones de un operador, se espera que su comportamiento sea diferente solo cuando el resultado de una operación sea demasiado grande para representar en el tipo de resultado como se indica a continuación:

  • Un operador comprobado produce un OverflowException.
  • Un operador sin el modificador checked devuelve una instancia que representa un resultado truncado.

Para obtener información sobre la diferencia en el comportamiento de los operadores aritméticos integrados, consulte la sección Desbordamiento aritmético y división por cero.

Puede usar el modificador checked solo cuando sobrecarga cualquiera de los operadores siguientes:

Nota

Un contexto de comprobación de desbordamiento dentro del cuerpo de un operador comprobado no se ve afectado por la presencia del modificador checked. El contexto predeterminado se define mediante el valor de la opción del compilador CheckForOverflowUnderflow . Use las instrucciones checked y unchecked para especificar explícitamente el contexto de comprobación de desbordamiento, como se muestra en el ejemplo al principio de esta sección.

Especificación del lenguaje C#

Para más información, vea las secciones siguientes de la Especificación del lenguaje C#:

Consulte también