Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么C#中的sin(x)函数返回NaN而不是数字_C#_Loops_Double_Nan_Trigonometry - Fatal编程技术网

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

为什么C#中的sin(x)函数返回NaN而不是数字,c#,loops,double,nan,trigonometry,C#,Loops,Double,Nan,Trigonometry,我用C#写了这个函数来计算sin(x)。但是当我尝试使用x=3.14时,sin x的打印结果是NaN(不是数字), 但在调试时,它非常接近于0.001592653 这个值不是太大,也不是太小。那南怎么会出现在这里呢 static double pow(double x, int mu) { if (mu == 0) return 1; if (mu == 1) retu

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

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);
            }
        }
静态双功率(双x,整数μ)
{
if(mu==0)
返回1;
if(mu==1)
返回x;
返回x*pow(x,mu-1);
}
静态双事实(int n)
{
如果(n==1 | | n==0)
返回1;
返回n*事实(n-1);
}
静态双正弦(双x)
{
var s=x;
对于(int i=1;i<1000;i++)
{
s+=pow(-1,i)*pow(x,2*i+1)/事实(2*i+1);
}
返回s;
}
公共静态void Main(字符串[]参数)
{
尝试
{
while(true)
{
Console.WriteLine(“输入x值:”);
double x=double.Parse(Console.ReadLine());
var sinX=sin(x);
WriteLine({0}的Sin是{1}:,x,sinX);
Console.ReadLine();
}
}
捕获(例外情况除外)
{
控制台写入线(例如消息);
}
}

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

在我的例子中,是当
x=4
i=256

请注意,
pow(x,2*i+1)
=
4^(2*257)
=-一个非常大的数字,刚好超过一个双精度的最大值,约为1.79769313486232 x 10^308

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


还要注意,
fact(2*i+1)=513=
大于
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;
    }
静态双正弦(双x)
{
var s=x;
对于(int i=1;i<1000;i++)
{
var项=功率(x,2*i+1)/事实(2*i+1);
如果(术语<1e-17)
打破
s+=功率(-1,i)*项;
}
返回s;
}

X的值是多少?我使用了1的值,结果是0.8414709848078965-解释重现问题的步骤..我使用x=3.14,这会使错误发生OK,可能是我必须更改算法:)我想为基准编写这个函数,不是为了计算的目的:)使用ILSpy,看看Math.Sin的内部实现。我认为verdana没有使用
Math.Sin
,因为练习的目的是将Sin函数作为一个系列来计算。@JeremyCompson所有的trig函数都是在CLR中以利用该平台的本机代码实现的能力,所以ILSpy不会告诉你任何有用的东西。