2017-07-26 64 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