为什么C#中的sin(x)函数返回NaN而不是数字

时间:2016-01-15 01:22:22

标签: c# loops double nan sin

我在C#中写了这个函数来计算sin(x)。但是当我尝试使用x = 3.14时,sin X的打印结果是NaN(不是数字), 但在调试时,它非常接近0.001592653 价值不是太大,也不是太小。那么NaN怎么会出现在这里呢?

{{1}}

3 个答案:

答案 0 :(得分:3)

失败是因为pow(x, 2 * i + 1)fact(2 * i + 1)最终都返回Infinity

就我而言,它是x = 4i = 256

请注意pow(x, 2 * i + 1) = 4 ^ (2 * 257) = 2.8763090157797054523668883052624395737887631663 × 10^309 - 一个愚蠢的大数字,刚刚超过双精度的最大值,大约是1.79769313486232 x 10 ^ 308。

您可能只想使用Math.Sin(x)

另请注意,fact(2 * i + 1) = 513! = an even more ridiculously large numberestimated number of atoms in the observable universe10^1000倍。

答案 1 :(得分:2)

当x == 3.14且i == 314时,你得到无限:

?pow(-1, 314)
1.0
?pow(x, 2 * 314 + 1)
Infinity
? fact(2 * 314 + 1)
Infinity

答案 2 :(得分:0)

这里的问题是理解“真实”的浮点表示。数字。

允许大范围值的双数字仅具有15到17个十进制数字的精度。

在这个例子中,我们计算的值介于-1和1之间。

我们通过使用它的系列展开来计算sin函数的值,它基本上是项的和。在那次扩张中,随着我们的进展,这些术语变得越来越小。

当条款达到小于1e-17的值时,将它们添加到已经存在的值将不会产生任何差异。这是因为我们只有52位的精度,当我们达到小于1e-17的时间时就会​​消耗掉。

因此,不应该做一个恒定的1000循环,你应该做这样的事情:

 static double sin(double x)
    {
        var s = x;

        for (int i = 1; i < 1000; i++)
        {
            var term = pow(x, 2 * i + 1) / fact(2 * i + 1);

            if (term < 1e-17)
               break;

            s += pow(-1, i) * term;
        }
        return s;
    }