Operadores aritméticos (referencia de C#)
Los operadores siguientes realizan operaciones aritméticas con operandos de tipos numéricos:
- Operadores unarios
++
(incremento),--
(decremento),+
(más) y-
(menos). - Operadores binarios
*
(multiplicación),/
(división),%
(resto),+
(suma) y-
(resta).
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 x
antes 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 x
despué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 x
antes 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: 2
Operador de decremento de prefijo
El resultado de --x
es el valor de x
despué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 dex
; - el valor absoluto de
z
es el valor producido por|x| - n * |y|
, donden
es el entero más grande posible que sea menor o igual que|x| / |y|
, y|x|
e|y|
son los valores absolutos dex
ey
, 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 decrementox--
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:
- Operadores
++
unarios,--
y-
- Operadores binarios
*
,/
,+
y-
- Operadores de conversión explícitos
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#:
- Operadores de incremento y decremento posfijos
- Operadores de incremento y decremento prefijos
- Operador unario más
- Operador unario menos
- Operador de multiplicación
- Operador de división
- Operador de resto
- Operador de suma
- Operador de resta
- Asignación compuesta
- Operadores checked y unchecked
- Promociones numéricas