我正在用 C 語言撰寫一個程式,該程式將玫瑰曲線繪制為 ASCII 藝術。該程式使用自定義三角函式(準確地說是泰勒級數):
int factorial(int n) {
int p = 1;
if (n == 0) return 1;
for (int i = 1; i < n; i ){
p *= i;
}
return p;
}
float sine(float x, int t) {
float s = 0;
for (int i = 0; i < t; i ) {
float n = (i%2==0 ? 1 : -1);
int d = factorial(i*2);
float m = pow(x, i*2);
s = (n/d)*m;
}
}
float cosine(float x, int t) {
float s = 0;
for (int i = 0; i < t; i ) {
float n = (i%2==0 ? 1 : -1);
int d = factorial(i*2 1);
float m = pow(x, i*2 1);
s = (n/d)*m;
}
t 引數表示項的數量,始終為 10。
為了繪制我使用的玫瑰圖:
void point(float r, float theta) {
float fx = r*cosine(theta, TM);
float fy = r*sine(theta, TM);
int x = (int) round(fx) 50;
int y = (int) round(fy) 50;
grid[x][y] = 1;
}
...other code...
for (float theta = 0; theta < PI; theta = 0.5) {
float r = SCALE*cosine(theta*CT, TM);
point(r, theta);
SCALE 變數是玫瑰的大小,在程式頂部定義。TM 變數是泰勒級數中的項數,CT 變數是另一個引數。使用默認的 C 觸發函式可以正常作業,但是當我切換到我的時,它給了我一個總線錯誤,上面寫著
make: *** [run] Bus error: 10
. 順便說一下,這是在 Mac OS X 10 上。我撰寫的函式為我提供了一些數字的正確值,但在這里不起作用。
我正在使用的泰勒級數在這里,我的實作以弧度作業:

如果您想知道為什么我不只使用默認的三角函式,我這樣做是為了好玩,自定義三角函式是我想為這個專案做的一部分。我也不是最有經驗的 C 程式員,所以請記住這一點。
uj5u.com熱心網友回復:
至少這些問題
未啟用所有警告
OP 最大的錯誤是沒有使用手頭的工具。啟用所有警告以快速識別問題,例如:
warning: conversion from 'double' to 'float' may change value [-Wfloat-conversion]
float m = pow(x, i*2);
warning: control reaches end of non-void function [-Wreturn-type]
int溢位
代碼呼叫factorial(20)超出int范圍。有符號整數溢位是未定義的行為(UB)。
缺少回傳值sine()
@Spektre
正弦計算錯誤
即使有一個小t的和一個附加的return s;,sine()也是不對的。
建議的重寫不會輕易溢位,并通過term基于先前更新每次迭代來避免重復計算term。
float sine_alt(float x, int t) {
float x2m = -x*x; // - to alternate term's sign.
float s = x;
float term = x;
for (int i = 1; i < t; i ) {
int i2 = i*2;
term *= x2m/(i2 * (i2 1));
s = term;
}
return s;
}
float對比double
對于float物件,通常使用float數學而不是double數學。
// pow(x, i*2 1);
powf(x, i*2 1);
uj5u.com熱心網友回復:
你的測角計算浪費了太多的 CPU 能力
請參閱C 函式以使用泰勒級數展開逼近正弦
你一次又一次地計算相同的東西,你混合
int并float導致緩慢的轉換......有多大
TM?你知道階乘溢位很快,在浮點數上你不能得到比 5 位小數更好的精度,不管 TM 是什么,所以我不敢超過
15......你不
return重視float和sinecosine這很可能會破壞堆疊并導致您的錯誤,因為其余代碼都在預期它,但我沒有在您的平臺上編碼,所以我可能是錯的......更好的編譯器會對此發出警告......
如果沒有
return你的 sin 和 cos ,即使你計算它也不會將結果傳播到你的代碼的其余部分。相反,您很可能會從 STACK 中得到亂碼,導致看似隨機的數字或什INF至或NAN...
因此,只需像這樣修復您的功能(希望我從上面的鏈接正確地將其移植到 C):
float sine(float x,int n=15)
{
int i;
float y=0; // result
float x2=x*x; // x^2
float xi=x; // x^i
float ii=1; // i!
if (n>0) for(i=1;;)
{
y =xi/ii; xi*=x2; i ; ii*=i; i ; ii*=i; n--; if (!n) break;
y-=xi/ii; xi*=x2; i ; ii*=i; i ; ii*=i; n--; if (!n) break;
}
return y;
}
cosine正如您所看到的,不需要像模數這樣的昂貴操作,也不需要像您一樣在每次迭代中呼叫子函式或重復計算相同的東西......不要忘記修復你的
uj5u.com熱心網友回復:
好的,所以當我在 MacOS 上看到“總線錯誤:10”時,我的第一個想法是您的程式試圖錯誤地訪問記憶體地址。
(另一個告訴我大致相同的一般要點的常見錯誤是“分段錯誤/違規”。您可以在其他問題中查找哪個系統上的含義存在細微差別。)
現在我們知道了,我們可以顯著縮小可能的原因!它必須是代碼中您的記憶體訪問可能針對錯誤記憶體的地方。
查看您最初發布的代碼,我能看到的唯一可能發生的地方是分配給grid[x][y].
所以我的下一個想法是:怎么可能x或y最終超出您分配的網格空間?我假設grid已經知道固定尺寸,并且相信您的說法,即您更改觸發問題的唯一方法是交換您使用的觸發函式。
基于此,我認為您的三角函式可能回傳的值最終(由于舍入或近似或其他原因)導致x或y超出網格。
要進一步除錯,您可以做的最簡單的事情是printf("x=%d y=%d\n", x, y);在您擁有的行之前添加一行grid[x][y]。然后根據它告訴你的內容,從那里開始。當值變得錯誤時,將您的陳述句添加/移動printf到其他地方以縮小范圍等等。
另外,我之前錯過了這個,感謝評論抓住它,但你發布的功能缺少任何return宣告。如果這在您的代碼中是正確的,并且您沒有將您的東西配置為在這種情況下出錯,那肯定會導致您在任何時候都看到明顯或微妙的錯誤結果。(要了解有關可能出錯的所有方式的更多資訊,您需要的一些搜索詞是“呼叫約定”和“ABI”。)
(您可能還想花時間熟悉如何在除錯器下實時運行您的程式,以便您可以看到變數值隨著代碼逐步執行每條指令而發生變化,但這是另一個學習曲線的單獨繞道。例如,如果缺少 return 陳述句是您的問題,并且您知道在除錯器中查找什么,例如當您的函式回傳時回傳值在某個暫存器中,您可能會很快注意到意外省略的return陳述句。)
另外,基于StackOverflow 推薦的這個相關問題,聽起來泰勒級數在離零太遠時可能天生就太不準確了?可能與這里有關。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/464880.html
