#cshap#computeException 当算术运算的结果超出所涉及数值类型的可能有限值范围时,算术运算符的行为取决于其操作数的类型。

整数算术溢出

整数被零除总是引发 DivideByZeroException

如果发生整数算术溢出,溢出检查上下文(可能已检查或未检查)将控制引发的行为:

  • 在已检查的上下文中,如果在常数表达式中发生溢出,则会发生编译时错误。 否则,当在运行时执行此运算时,则引发 OverflowException
  • 在未检查的上下文中,会通过丢弃任何不适应目标类型的高序位来将结果截断。

在使用 checked 和 unchecked 语句时,可以使用 checked 和 unchecked 运算符来控制溢出检查上下文,在该上下文中将计算一个表达式:

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

默认情况下,算术运算发生在 unchecked 上下文中。

浮点运算溢出

使用 float 和 double 类型的算术运算永远不会引发异常。 使用这些类型的算术运算的结果可能是表示无穷大和非数字的特殊值之一:

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

对于 decimal 类型的操作数,算术溢出始终会引发 OverflowException。 被零除总是引发 DivideByZeroException

舍入误差

由于实数和浮点运算的浮点表达形式的常规限制,在使用浮点类型的计算中可能会发生舍入误差。 也就是说,表达式得出的结果可能与预期的数学运算结果不同。 以下示例演示了几种此类情况:

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