如何检查 Math.cos(angle) 是否等于 0?

4

我正在尝试找到tan函数的正确定义域,我知道

tan x = sinx / cos x

cos x = 0时,tan是未定义的。因此,我正在尝试检查cos x是否为0。

 if ( Math.Cos(x).Equals(0) )
 {
     // do stuff
 }

但这并不是真的,因为 Math.Cos 返回 6.123....E-17。如何检查 cos == 0?


由于这里使用了双精度,你应该添加一个合理的误差范围。 - Daniel A. White
很奇怪之前没有人尝试过比较双精度浮点数...http://www.bing.com/search?q=C%23+double+compare 似乎产生了一些结果 - 可能这不是第一次... - Alexei Levenkov
1
当参数恰好为+/- pi/2时,结果才恰好为0。然而浮点数精度不足,因此这种情况几乎不会出现。 - Hans Passant
为什么不检查一下x的值,确保它与pi/2 + kpi不同呢? - Francesco De Lisi
@FDL 我考虑过这个问题,但不知道如何进行检查。 - giannisf
由于您的x是以弧度表示的,因此您必须使用x * 180 / Math.PI转换为度数。例如,如果x == 1.57 rad,则您将拥有90度,而您的cos(90)== 0,实际上90度== Math.PI / 2。 - Francesco De Lisi
3个回答

11

你需要稍微扩大一下期望范围 - 为了让Math.Cos(x)真正等于0,你要么需要在Cos中出现不准确性(当然这种情况会发生),要么就需要x具有无理数值。

相反,你应该计算出一些容差 - 一些非常接近0的Math.Cos数值范围。例如:

if (Math.Abs(Math.Cos(x)) < 1e-15)

那个1e-15基本上是任意选定的 - 你应该计算出你特定任务所需的值。(当然,这仍会产生相当巨大的tan值......)


使用 double.Epsilon 怎么样? - user1620220
2
double.Epsilon太小了。 - Matthew Watson
@user1620220:不,那可能太小了。特别地,“仅仅”值为0、double.Epsilon-double.Epsilon 是在 double.Epsilon 范围内的...并且我不确定是否存在一个 doublex 使得 Cos(x) 是这三��值之一。 - Jon Skeet
3
double.Epsilon不是模糊比较的epsilon,而是在双精度浮点数中表示的最小非零值。 - JustSomeGuy
1
值得注意的是,通常这些阈值(例如:1e-15)往往取决于后续计算的性质。在某些情况下(多重导数等),为了避免随后的计算中数字爆炸,您实际上必须比其他情况更早地截断。您的整个系统将具有“一般可计算”的域,您通常需要在每种情况下确定该域是什么。 - J...
显示剩余4条评论

4

如果您遇到了从Math.Tan接收异常的问题,那么需要说明的是,Math.Tan不会抛出异常。它能够做的唯一一件事是返回Double.NaN以及(也许)Double.PositiveInfinity/Double.NegativeInfinity,所以只需要检查它们即可:

double t = Math.Tan(something);

if (!double.IsInfinity(t) && !double.IsNaN(t))
{
    // Do Something
}

2

问题在于你需要进行比较,但由于浮点数在内存中的表示方式,你不能直接进行比较,需要有一定的精度。

你可以使用以下代码来解决这个问题:

const double Epsilon = 0.0001;

if (Math.Cos(x) < Epsilon)
{
    // Code here
}

此外,写Math.Cos(x).Equals(something)是没有意义的,因为这会使代码更难读懂。
如果您想获得关于代码为什么无法正常工作的更多信息,您可以在此处查找:http://www.parashift.com/c++-faq/floating-point-arith.html 这是一个C ++的FAQ,但在您的情况下同样适用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接