[英]Why this sin(x) function in C# return NaN instead of a number
我用C#编写了此函数来计算sin(x)。 但是,当我尝试使用x = 3.14时,sin X的打印结果是NaN(不是数字),但是在调试时,它的值非常接近0.001592653。该值不会太大,也不会太小。 那么NaN怎么会出现在这里?
static double pow(double x, int mu)
{
if (mu == 0)
return 1;
if (mu == 1)
return x;
return x * pow(x, mu - 1);
}
static double fact(int n)
{
if (n == 1 || n == 0)
return 1;
return n * fact(n - 1);
}
static double sin(double x)
{
var s = x;
for (int i = 1; i < 1000; i++)
{
s += pow(-1, i) * pow(x, 2 * i + 1) / fact(2 * i + 1);
}
return s;
}
public static void Main(String[] param)
{
try
{
while (true)
{
Console.WriteLine("Enter x value: ");
double x = double.Parse(Console.ReadLine());
var sinX = sin(x);
Console.WriteLine("Sin of {0} is {1}: " , x , sinX);
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
之所以失败,是因为pow(x, 2 * i + 1)
和fact(2 * i + 1)
最终都返回Infinity
。
就我而言,是x = 4
, i = 256
。
请注意, pow(x, 2 * i + 1)
= 4 ^ (2 * 257)
= 2.8763090157797054523668883052624395737887631663×10 ^ 309-一个非常大的数字,刚好超过double的最大值,大约是1.79769313486232 x 10 ^ 308 。
您可能只对Math.Sin(x)
感兴趣
另请注意, fact(2 * i + 1) = 513! =
fact(2 * i + 1) = 513! =
an even more ridiculously large number
,比可观察的宇宙中估计的原子数大10^1000
倍。
当x == 3.14并且i == 314时,您得到无穷大:
?pow(-1, 314)
1.0
?pow(x, 2 * 314 + 1)
Infinity
? fact(2 * 314 + 1)
Infinity
这里的问题是对“实数”的浮点表示的理解。
双精度数字同时允许较大范围的值,其精度只能为15到17个十进制数字。
在此示例中,我们正在计算介于-1和1之间的值。
我们使用正弦函数的级数展开来计算正弦函数的值,该函数基本上是项的和。 在这种扩展中,术语随着我们的发展而变得越来越小。
当术语的值小于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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.