2011-07-31 24 views
6

由于PI/2不能精确表示为浮点数,因此假设cos(a)永远不会返回精确的零值是否安全?可以cos(a)在浮点数中等于0

如果是这样的话,那么下面的伪代码将不会进入块(它可以安全地删除):

... 
y = h/cos(a); 
if (!isfinite(a)) 
{ 
    // handle infinite y 
} 
+0

有时系统可能迫使当“a”是aprox时为零。等于'pi/2'。 – ja72

回答

4

零是可以准确表示的几个值之一。许多系统都有一个查找表,以查看sin和cos的常见值,因此不可能返回正好为零的值。

但你是更安全的使用增量比较,执行分立前:

if (Abs(cos(a)) < 0.0000001) 
{ 

} 
+2

“几个”之一? (2^64 - 2^53)我不认为我会用“几个”这个词。 –

+0

1/2,1/4,1/8,..... –

+1

每个有限浮点值都可以精确地用浮点数表示(令人震惊,我知道)。不仅是1/2,1/4,还有0.333333333333333314829616256247390992939472198486328125和3.141592653589790007373494518105871975421905517578125。 –

0

没有,这个不能保证,因为cos本身与计算一个错误,所以它的值可以很容易地精确为零。

7

大于零,即最接近来π/ 2的倍数的双精度值是6381956970095103 * 2^797其他,它等于:

(an odd integer) * π/2 + 2.983942503748063...e−19 

因此,对于所有双精度值x,我们有界:

|cos(x)| >= cos(2.983942503748063...e−19) 

请注意,这是数学上精确值的界限,而不是库函数cos返回的值。在具有高质量数学库的平台上,这个界限足够好,我们可以说cos(x)对于任何双精度x都不为零。事实上,事实证明,这不是双重的唯一;此属性适用于所有IEEE-754基本类型,如果cos被忠实舍入。

但是,这并不是说在一个三角函数减少实现极其糟糕的平台上不会发生这种情况。

更重要的是,它的关键要注意,在你的榜样y可以是无限的没有cos(a)为零:

#include <math.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) { 
    double a = 0x1.6ac5b262ca1ffp+849; 
    double h = 0x1.0p1022; 
    printf("cos(a) = %g\n", cos(a)); 
    printf("h/cos(a) = %g\n", h/cos(a)); 
    return 0; 
} 

编译和运行:

scanon$ clang example.c && ./a.out 
cos(a) = -4.68717e-19 
h/cos(a) = -inf 
+0

我本来很想回答这个问题,在它旁边提供了一些线索,为什么0.0000001这样的容忍听起来完全是任意的,它甚至不能防止溢出。溢出保护应该像if(abs(cos(x))<1);) –