2017-07-26 62 views
0

我试图在没有使用Math.sin(x)的Java中实现正弦函数。所以我试图用泰勒系列来实现这一点。不幸的是,这段代码给出了错误的结果。在没有Math.sin功能的Java中实现Sine

如果你不知道泰勒级数是什么,看看:

下面的代码片段,我创建:

public static double sin(double a) { 
    double temp = 1; 
    int denominator = -1; 
    if(a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) { 
     return Double.NaN; 
    } 
    if(a != 0) { 
     for (int i = 0; i <= a; i++) { 
     denominator += 2; 
     if(i % 2 == 0) { 
      temp = temp + (Math.pow(a, denominator)/Factorial.factorial(denominator)); 
     } else { 
      temp = temp - (Math.pow(a, denominator)/Factorial.factorial(denominator)); 
     } 
     } 
    } 
    return temp; 
} 

我不能发现我犯的错误。你做?

+1

你期望什么样的结果,而你是怎么得到?你到目前为止做了哪些调试? –

+1

为什么术语的数量取决于'a'的值?这与你提供的泰勒展开不一致。 – bradimus

+1

问题出在'i <= a' – talex

回答

0

你的代码有两个主要问题。第一个问题是,您正在从0循环ia。这意味着,如果a是负值,则for循环甚至不会启动,并且结果将始终为1.0。而如果a是肯定的,则循环开始,但在迭代后停止,并且它没有多大意义,因为当迭代n倾向于无穷大时,泰勒apporximation可以正常工作。

第二个主要问题是您没有对输入值a进行足够的控制。 正如我在Python: Calculate sine/cosine with a precision of up to 1 million digits

真正的泰勒展开中X中心已经说是:

enter image description here

其中Rn中Lagrange余

enter image description here

注意Rn中尽快从中心 X0X移开增长较快。

既然你正在实施麦克劳林系列(以0为中心的泰勒级数 ),而不是一般的泰勒级数,你的函数 将尝试计算罪当给真正错误的结果(X)为 大值x

所以for循环前,必须将域减少到至少[-pi,PI] ...更好,如果你将其降低到[0,PI]和利用正弦的平价。

工作代码:

public static double sin(double a) { 

    if (a == Double.NEGATIVE_INFINITY || !(a < Double.POSITIVE_INFINITY)) { 
     return Double.NaN; 
    } 

    // If you can't use Math.PI neither, 
    // you'll have to create your own PI 
    final double PI = 3.14159265358979323846; 

    // Fix the domain for a... 

    // Sine is a periodic function with period = 2*PI 
    a %= 2 * PI; 
    // Any negative angle can be brought back 
    // to it's equivalent positive angle 
    if (a < 0) { 
     a = 2 * PI - a; 
    } 
    // Also sine is an odd function... 
    // let's take advantage of it. 
    int sign = 1; 
    if (a > PI) { 
     a -= PI; 
     sign = -1; 
    } 
    // Now a is in range [0, pi]. 


    // Calculate sin(a) 

    // Set precision to fit your needs. 
    // Note that 171! > Double.MAX_VALUE, so 
    // don't set PRECISION to anything greater 
    // than 84 unless you are sure your 
    // Factorial.factorial() can handle it 
    final int PRECISION = 50; 
    double temp = 0; 
    for (int i = 0; i <= PRECISION; i++) { 
     temp += Math.pow(-1, i) * (Math.pow(a, 2 * i + 1)/Factorial.factorial(2 * i + 1)); 
    } 

    return sign * temp; 

} 
1

您的问题是您正在使用正弦函数的分析值作为分母的限值。泰勒级数被评估为函数的极限接近无穷大。在这种情况下,您只是对输入值的大小进行评估,这并不合理。您应该将for循环比较替换为i < x,其中x是一个表示您希望生成的精度的常量(该函数对于低至20左右的值来说相当准确)。

+1

事实上,当你在某个点上增加'x'函数开始失去精度时,因为数字的有限表示变得越来越不精确。 – talex