2011-08-01 88 views
1

简单的问题,我有以下的C程序:约“浮点异常”用C

#include <stdio.h> 

int main() 
{ 
double x=0; 
double y=0/x; 
if (y==1) 
    printf("y=1\n"); 
else 
    printf("y=%f\n",y); 
if (y!=1) 
    printf("y!=1\n"); 
else 
    printf("y=%f\n",y); 

return 0; 
} 

我得到的输出是

y=nan 
y!=1 

但是,当我更改线路 双X = 0 ; 至 int x = 0; 输出变为

Floating point exception 

任何人都可以解释,为什么?

+3

什么时候所有关于精度,双精度,小数点和浮点数的问题都会消失? http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html – JonH

+0

您除以零,这是不允许的。 –

回答

0

有一个在IEE754一个特殊的位模式这表明NaN零个误差浮点相除的结果。

但是在使用整数算术时没有这样的表示,所以系统必须抛出异常而不是返回NaN

+0

好吧,我明白了,但为什么呢?为什么浮点除以零而不是整数? – Moshe

+0

,因为在完成后可能会检测到浮点除法的'NaN'结果。除了通过测试零除数_before_执行除法之外,没有办法通过整数结果来做到这一点。 – Alnitak

2

你造成分裂0/0与整数运算(这是无效的,并产生你看到的除外)。不管y的类型,首先评估的是0/x

x被声明为double时,零也转换为double,并且该操作使用浮点算法执行。

x被声明为int时,您将一个int 0除以另一个,并且结果无效。

0

整数除以0是非法的,不处理。另一方面,浮动值在C中使用NaN进行处理。以下如何将工作。

int x=0; 
double y = 0.0/x; 
+0

这很明显,因为'y'现在是双倍。该运算已经有了。 – JonH

+2

@JonH它可能不像你想象的那么明显,特别是因为double值是使用文字整数常量设置的。 :) – Joe

1

因为由于IEEE 754,NaN的将进行上浮点数非法操作(例如0/0∞×0,或sqrt(−1))时产生的。

实际上有两种NaNs,信令和安静。在任何算术运算(包括数字 比较)中使用信号NaN使用 将导致“无效”异常。使用安静的NaN 只会导致结果为NaN。

由标准指定的NaN表示有一些 未指定的位,可用于编码错误类型;但是 这个编码没有标准。理论上,运行时系统可以使用信号发送器来扩展具有其他特殊值的浮点数 ,而不会使用普通值减慢计算。虽然这样的扩展似乎并不常见。

此外,维基百科说,这大约integer division by zero

整数除以零通常是由浮动 点,因为有对结果没有整数表示处理方式不同。某些 处理器会在尝试将整数除以零时尝试生成一个异常,但其他处理器会简单地继续并生成一个 不正确的除法结果。结果取决于如何实现分区 ,并且可以是零,有时可能是最大的可能整数。

-1

浮点本质上是将实数建模为有限的精度。只有有限数量的位模式,但是无数(连续!)数量的实数。它尽其所能,将最接近的可表示的实数返回给它的确切输入。太小而不能直接表示的答案用零表示。除以零是实数中的错误。然而,在浮点数中,因为这些非常小的答案可能会产生零,所以将x/0.0(对于正x)看作“正无穷大”或“太大而不能表示”会很有用。这对于x = 0.0不再有用。

我们可以说的最好的一点是,零除零实际上是“将除零之外无法区分的小东西与零之外的东西区分开来”。这个答案是什么?那么,0/0的确切情况是没有答案的,并且没有很好的方法来处理它。这取决于相对的幅度,因此处理器基本上耸耸肩说,“我失去了所有的精度 - 我给你的任何结果都会误导”,通过返回非数字。

相比之下,当进行整数除零时,除数确实只能表示精确为零。没有办法给它一个一致的含义,所以当你的代码要求答案时,它确实在做非法的事情。

(这是第二种情况下的整数除法,但不是第一种,因为C的升级规则可以看作整数字面值,而且由于两边都是整数,所以除法是整数除法。第一种情况下,事实x是一个双重原因红利将提升一倍。如果通过0.0更换0,这将是一个浮点除法,不管的x类型。)

+0

您的第一段*非常*误导。 IEEE-754浮点中的基本算术运算将它们的论点看作是精确的。零确实意味着完全为零。 '0.0/0.0'不会产生NaN,因为“它可能不是零”;它会产生NaN,因为没有唯一的数字x,其中0 = 0 * x。 –

+0

@Stephen Canon:当然,FP将输入视为精确,并在存在时返回最接近的可表示真实。但他们没有无限的精确度。如果确切答案不可表示,计算中可能出现零点;这确实激发了零除法的处理。考虑正x的x/0的情况:它给出+无穷大。这不是因为无限* 0是任何x,而是真正将零视为“非常小”(无限大为“非常大”)。这种行为是有用的和有意义的,但是对于x = 0就停止了。 – wnoise

+0

对不起,但那是不正确的。在我的评论中,我有点快速和松散,但这仍然是错误的。零不被视为“非常小”。实际发生的情况是,a/x在x = 0时在数学上未定义,但函数通过以x - > 0+为极限的连续性来扩展。这个限制不是通常的实数,而是实数的两点压缩,所以它是+无穷大。如果0仅仅被视为“非常小”,那么被零除的信号会溢出。但是,它没有;结果是*精确*无穷大。 –

0

如果您除以intint即可除以0.

0/0双打是NaN

int x=0; 
double y=0/x; //0/0 as ints **after that** casted to double. You can use 
double z=0.0/x; //or 
double t=0/(double)x; // to avoid exception and get NaN