这是一个使用来自this blog的泰勒级数逼近反正弦(x)的公式
这是我在C#中的实现,我不知道哪里出错了,运行时代码给出了错误的结果: 当i = 0时,除法将为1 / x。所以我在启动时分配temp = 1 / x。对于每次迭代,我在“i”之后改变“temp”。 我使用连续循环,直到下一个两个值非常“接近”在一起。当两个下一个数字的增量非常小时,我将返回该值。
我的测试用例: 输入为x = 1,因此除了arcsin(X)将是arcsin(1)= PI / 2 = 1.57079633 rad。
class Arc{
static double abs(double x)
{
return x >= 0 ? x : -x;
}
static double pow(double mu, long n)
{
double kq = mu;
for(long i = 2; i<= n; i++)
{
kq *= mu;
}
return kq;
}
static long fact(long n)
{
long gt = 1;
for (long i = 2; i <= n; i++) {
gt *= i;
}
return gt;
}
#region arcsin
static double arcsinX(double x) {
int i = 0;
double temp = 0;
while (true)
{
//i++;
var iFactSquare = fact(i) * fact(i);
var tempNew = (double)fact(2 * i) / (pow(4, i) * iFactSquare * (2*i+1)) * pow(x, 2 * i + 1) ;
if (abs(tempNew - temp) < 0.00000001)
{
return tempNew;
}
temp = tempNew;
i++;
}
}
public static void Main(){
Console.WriteLine(arcsin());
Console.ReadLine();
}
}
答案 0 :(得分:4)
在许多系列评估中,使用术语之间的商来更新术语通常很方便。这里的商是
(2n)!*x^(2n+1) 4^(n-1)*((n-1)!)^2*(2n-1)
a[n]/a[n-1] = ------------------- * --------------------- -------
(4^n*(n!)^2*(2n+1)) (2n-2)!*x^(2n-1)
=(2n(2n-1)²x²)/(4n²(2n+1))
= ((2n-1)²x²)/(2n(2n+1))
因此,计算序列值的循环是
sum = 1;
term = 1;
n=1;
while(1 != 1+term) {
term *= (n-0.5)*(n-0.5)*x*x/(n*(n+0.5));
sum += term;
n += 1;
}
return x*sum;
仅abs(x)<1
保证收敛,对于x=1
的评估,您必须采用角度减半,这通常是加速收敛的好主意。
答案 1 :(得分:3)
您正在保存两个不同的临时值(temp和tempNew)以检查继续计算是否无关紧要。这很好,除了你没有保存这两个值的总和。
这是一个总结。您需要将每个新计算值添加到总计中。您只跟踪最近计算的值。您只能返回系列的最后一个计算值。所以你总会得到一个非常小的数字作为你的结果。将其转换为总和,问题应该消失。
答案 2 :(得分:2)
注意:我已经将此作为社区维基的答案,因为我不是第一个想到这一点的人(只是第一个将其记在评论中)。如果您觉得需要添加更多内容才能完成答案,只需在其中进行编辑即可!
普遍怀疑这是Integer Overflow,即您的一个值(可能是fact()
或iFactSquare()
的回报)对于您选择的类型来说太大了。由于您使用的是签名类型,因此它会变为负数 - 当它变为过大的正数时,它会循环回到负数。
尝试跟踪计算过程中n
的大小,并确定如果您通过fact
,pow
和{{1}运行该数字,它会给您带来多大的数字}} 功能。如果它比我们想象的Maximum long value in 64-bit更大(假设您使用的是64位,那么对于32位来说它会小得多),那么请尝试使用{{ 3}}