不同值类型之间的除零行为不一致

时间:2011-01-05 22:07:31

标签: c# .net vb.net .net-3.5 divide-by-zero

请考虑以下代码和评论:

Console.WriteLine(1 / 0); // will not compile, error: Division by constant zero

int i = 0;
Console.WriteLine(1 / i); // compiles, runs, throws: DivideByZeroException

double d = 0;
Console.WriteLine(1 / d); // compiles, runs, results in: Infinity   

我可以理解编译器在运行时主动检查除零除常数和DivideByZeroException但是:

为什么在“除零”中使用双精度返回Infinity而不是抛出异常?这是设计还是错误?

只是为了踢,我也是在VB.NET中做到了这一点,结果是“更一致”:

dim d as double = 0.0
Console.WriteLine(1 / d) ' compiles, runs, results in: Infinity

dim i as Integer = 0
Console.WriteLine(1 / i) '  compiles, runs, results in: Infinity

Console.WriteLine(1 / 0) ' compiles, runs, results in: Infinity

修改

根据kekekela的反馈,我运行了以下操作,结果是无限:

Console.WriteLine(1 / .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001);

这个测试似乎证实了这个想法,0.0的字面翻倍实际上是一个非常非常微小的部分,它将导致无限......

5 个答案:

答案 0 :(得分:35)

简而言之:double类型定义了无穷大的值,而int类型则没有。因此,在double情况下,计算结果是一个值,您可以在给定类型中实际表达,因为它已定义。在int情况下,无穷大没有值,因此无法返回准确的结果。因此例外。

VB.NET做的事情略有不同;整数除法使用/运算符自动生成浮点值。这是为了允许开发人员编写例如表达式1 / 2,并将其评估为0.5,有些人会认为这是直观的。如果你想看到与C#一致的行为,试试这个:

Console.WriteLine(1 \ 0)

请注意上面使用整数除法运算符(\,而不是/)。我相信你会得到一个异常(或编译错误 - 不确定是哪个)。

同样,试试这个:

Dim x As Object = 1 / 0
Console.WriteLine(x.GetType())

以上代码将输出System.Double

至于关于不精确的观点,这是另一种看待它的方式。并不是double类型没有完全为零的值(它确实如此);相反,double类型并不意味着首先提供数学上精确的结果。 (某些值可以准确表示,是的。但计算不能保证准确性。)毕竟,数学表达式1 / 0的值未定义(最后我查了一下)。但是当{x接近零时,1 / x接近无穷大。因此,从这个角度来看,如果我们无法完全代表大多数分数n / m ,那么将x / 0案例视为近似并给出接近的值 - 再次,至少定义了无穷大。

答案 1 :(得分:7)

double是一个浮点数而不是一个精确的值,所以你真正从编译器的角度划分的是接近于零但不完全为零的东西。

答案 2 :(得分:2)

因为“数字”浮点不是那种。浮点运算:

  • 不是关联的
  • 不是分配
  • 可能没有乘法逆

(有关示例,请参阅http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-point.pdf

浮点是一个解决特定问题的构造,并且在它不应该的时候被全部使用。我认为它们非常糟糕,但这是主观的。

答案 3 :(得分:1)

这可能与IEEE标准浮点和双精度浮点数具有指定的“无穷大”值有关。 .NET只是暴露了硬件级别已经存在的东西。

请参阅kekekela的回答,为什么这在逻辑上是有道理的。

答案 4 :(得分:1)

这是设计原因,因为double类型符合IEEE 754,即浮点运算的标准。查看Double.NegativeInfinityDouble.PositiveInfinity的文档。

  

此常量的值是将正数{或负数}除以零的结果。