2016-10-04 53 views
1

我做了一個程序來計算各自的泰勒級數,但是教授希望我們通過先除,然後相乘來改變它。這是我的代碼,我使用divide()作爲第一部分。我的power()和fact()只是對舊代碼的引用。C中的泰勒級數,功能除以先乘後數

#include <stdio.h> 
#include <math.h> 

int main() 
{ 
double x, mySin(), myCos(), myExp(); 
char more; 

do  { 
    printf ("\n\t\t\t\t\tInput x: "); 
    scanf ("%lf", &x); 
    printf ("\n\t\t\t\t\t\t\tLibraryResult \t MyResult"); 
    printf ("\n\t\t\tSin(%6.2f)\t  %9.6f\t\t%9.6f", x, sin(x), mySin(x)); 
    printf ("\n\t\t\tCos(%6.2f)\t  %9.6f\t\t%9.6f", x, cos(x), myCos(x)); 
    printf ("\n\t\t\tExp(%6.2f)\t  %9.6f\t\t%9.6f", x, exp(x), myExp(x)); 
    printf ("\n\n\t\t\t\t\tDo more (Y/N) ?"); 
    scanf ("%s", &more); 
} while (more == 'y' || more == 'Y'); 
} 

double mySin(double x) 
{ 
double sum = 0., divide(); 
int i, sign = 1; 

for (i = 0; i < 30; i++, sign = - sign) 
    sum = sum + sign * divide(x) ; //power(x, 2 * i + 1)/fact(2 * i + 1); 

return sum; 
} 

double myCos(double x) 
{ 
double sum = 0., divide(); 
int i, sign = 1; 

for (i = 0; i < 30; i++, sign = - sign) 
    sum = sum + sign * divide(x);//power(x, 2 * i)/fact(2 * i); 

return sum; 

} 

double myExp(double x) 
{ 
double sum = 0., divide(); 
int i; 

for (i= 0; i < 30; i++) 
    sum = sum + divide(x); //power(x, i)/fact(i); 


return sum; 
} 


double divide(int n, double x) 
{ 
int i; 
double div = 1.; 

for (i = 1; i < n; i++) 
    div = x/i; 

return div; 

} 

/*double fact(int n) 
{ 
int i; 
double prod = 1.; 

for (i = 1; i <= n; i++) 
    prod = prod * i; 

return prod; 
} 

double power (double x, int n) 
{ 
int i; 
double prod = 1.; 

for (i = 0; i < n; i++) 
    prod = prod * x; 

return prod; 
} 
*/ 

我一直在用的代碼,當在除()插科打諢,用我<ň產生任何結果,當我輸入x。但是,使用我也可以,但計算錯誤。我試圖自己弄清楚這一點,所以只要一個指針會有幫助!謝謝!

+0

在'divide'函數中,'for'循環什麼都不做,因爲每次只覆蓋'div'的值。因此,函數相當於'return x /(n-1);'。也許你的意思是'div * = x/i;'。 – user3386109

+2

另外請注意,你的'divide'有兩個參數,'divide(int n,double x)',但你只用一個'sum = sum + sign * divide(x)'來調用它。這應該會給你一個錯誤,但是你聲明瞭一個'局部'除法爲'double sum = 0.,divide();'編譯器只是隨之而來,但是你只指定了x,所以它不知道該怎麼做與...一起做通過額外的'n',它應該開始變得更有意義。 – LambdaBeta

+0

一般提示避免LambdaBeta指出的問題:永遠不要將函數原型放在其他函數中,也絕不要指定函數原型。有兩種標準做法。 1)將所有函數原型放在文件的頂部。複製函數定義,將其粘貼到文件頂部並添加分號。 2)按相反順序排列功能。也就是說,'divide'是文件中的第一個,後面是'myCos','mySin','myExp','main'放在文件的末尾。這樣,函數定義就像函數原型一樣,避免了原型中的錯誤。 – user3386109

回答

1

我想我會給你一個答案,因爲你的問題是系統性的。

首先,將函數拉入前向聲明。沒有更多:

double x, mySin(), myCos(), myExp(); 

而是把這個上面int main()

double divide(int n, double x); 
double mySin(double x); 
double myCos(double x); 
double myExp(double x); 

這也爲您提供了一個很好的機會來記錄一下這些事。這實際上可以解決你的問題! (是的,即使文件只是一個評論):

// Returns x^n/n! 
double divide(int n, double x); 

望着那評論,突然mySin是沒有意義的:

sum = sum + sign * divide(x); // this is sum += sign * x^?/?! 

因此,修正mySin會是這個樣子:(注那拉邏輯跳出循環語句通常是一個好主意)

// The series for sin(x) starts with x^1/1 and continues by increasing by 2 
for (i = 1; i < 30; i += 2) { 
    sum += sign * divide(i,x); // += saves you from writing sum + ... 
    sign = -sign; 
} 

這將產生正確的輸出,但事實並非如此。不幸的是,您的divide()也存在問題。保持它的文檔記,讓我們來看看它:

double divide(int n, double x) 
{ 
int i; 
double div = 1.; 

for (i = 1; i < n; i++) 
    div = x/i; 

return div; 

} 

這是非常接近正確,它只是等號是不完全正確。我們希望每次迭代乘以x/i。

for (i = 1; i < n; i++) 
    div *= x/i; 

更接近,但讓我們算一下會循環多少次。它的n-1次(如果我們從0開始,它將是n次,但是我們會有一個除以0的錯誤)。讓我們來解決這個問題:

for (i = 1; i <= n; i++) 
    div *= x/i; 

現在這在技術上做師同時爲乘法,這將產生最準確的結果(通過保持DIV接近「正常」的數字)。如果你先分開,你會開始使用非常小的數字,如果你先乘,你會開始使用真正的大數字。無論哪種方式,你將失去準確性(因爲double在中等大小的數字上是最準確的)。如果您拆分環除了它變成:

鴻溝循環:

for (i = 1; i <= n; i++) 
    div /= i; 

多重循環:

for (i = 1; i <= n; i++) 
    div *= x; 

對於大多數的投入,就沒有太大的差別可言。但是,如果你有'極端'的價值觀,你最終會殺死你的雙打。例如,當第一次相乘時,如果使用x = 1000,則在實際開始分割之前,您將超出雙倍的空間。結果將是nan,因爲double不能處理它。同樣,如果你抽取迭代次數(而不是30次,做30000000次),它顯然需要更長的時間(當然是更長的10萬倍),但是如果你也先分開,你最終會在你的倍數。因此你會得到0的結果(注意:我沒有測試這個,這是理論)。編譯器也可以看到優化機會併爲您提供服務。