Anonymous
Anonymous asked in 電腦與網際網路程式設計 · 9 years ago

如何用C語言建立sine-table

我要使用C語言建立一個完整的sine-table(360度)

即一個週期

我要的解析度希望是1024個

希望會的大大能幫忙解決

小弟不才 懇請大家幫忙!!!

謝謝

Update:

就是, 我希望sin 0度~360度裡面 有1024個數值

我希望一個sin週期的解析度 越精密越好!!

謝謝回答唷^^ 感嗯!!

Update 2:

我想應該是我表達的不好><

我應該是要這一種的

f_sin(30) = 0.5

f_sin(45) = 0.707

f_sin(60) = 0.866

f_sin(x), x=0~360,

step = 360 / 1024,

只是 差別就是 我0~360度 要有1024個數值

應該就是1024/4=256 每90度我要有256個數值出現

往後的91~360度就是依照前90度去推算這樣

謝謝您耐心的回答唷^^

Update 3:

嗯嗯~不過還是希望切成1024份唷!! 謝謝您!!!

1 Answer

Rating
  • 9 years ago
    Favorite Answer

    你是要類似這種嗎?

    f_sin(30) = 0.5

    f_sin(45) = 0.707

    f_sin(60) = 0.866

    f_sin(x), x=0~360,

    step = 360 / 1024,

    是這個嗎?不是的話請詳述需求說明。

    2011-06-16 01:56:16 補充:

    「我認為」這題目或需求似乎不是非常好。

    首先若你是要「度度量」,我認為會較不好,

    因在數值分析中之三角函式都是以「弳度量」在算,

    也就是 f_sin(30度) 用 f_sin(PI * 30 / 180) = f_sin(0.523598...) 去計算,

    如果要換成「度度量」方式建表,那你要怎麼建?

    2011-06-16 01:56:20 補充:

    fsin(0), fsin(1)... fsin(1024) ??

    這樣你要怎麼對?

    fsin(90) = fsin(90度) = fsin(PI * 90 / 180) = fsin(1.570796327...) ??

    我數學、中文理解力有點差,可的話請舉例,

    如果連問題定義都不清楚,我想很難有人可以幫你。

    2011-06-16 02:01:38 補充:

    你可以想像一下,如果是度度量,

    fsin(100) 到底要對應到幾度?是對應到度度量還是弳度量?

    度度量的話代表 fsin(100度) = sin(100度)

    弳度量的話代表 fsin(100) = sin(100* 180/PI 度) = sin(5729.577951.. 度)

    = sin(329.577951...度)

    所以,你到底是要哪種對表?度度量?弳度量?引數只允許有整數出現?

    2011-06-16 18:23:33 補充:

    最後一個問題是,是否「一定」要切成 1024 份,

    這題「我覺得」似乎切成 720 / 1440 / 2880 份為佳。

    Why ? 浮點數誤差會較小!

    2011-06-16 19:43:20 補充:

    這題,要解得好,很難!

    以 1024 份為例,若是 360 / 240 = 0.3515625,

    這樣沒辦法對 table 進行 map 動作,

    此處再建立一 sin_index 去存各度度之數值,

    查到度度數值後,再到 sin_table 去查該數值為何。

    程式碼及其測試參考如下

    #include <stdio.h>

    #include <stdlib.h>

    #include <math.h>

    #include <time.h>

    /* 測試定義 */

    #define STEP 1E-5

    #define MAX 360

    #define OUT_EPS 7E-3 /* 結果容許誤差, 不合則輸出 */ /* 參數定義 */

    #define T_SIZE 1024 /* table 大小 */

    #define EPS 1E-9 /* 度度量最小容許誤差 */ /* 常數計算 */

    double PI;

    double interval;

    double deg_to_rad;// 度度轉弳度常數 /* 對應之表 */

    double sin_table[T_SIZE]={0};

    double sin_index[T_SIZE]={0};

    void sin_init()

    {

    int i;

    PI = 2*acos(0.0);

    interval = 360.0 / T_SIZE;

    deg_to_rad = PI / 180;

    for(i=0; i!=T_SIZE; ++i) {

    sin_index[i] = i*interval;

    sin_table[i] = sin( sin_index[i] * deg_to_rad );

    }

    } double sin_lookup(double deg)

    {

    int index;

    deg = fmod(deg, 360.0); // 先將 deg 化為主角

    index = floor(deg/interval); // 計算所在 index

    return sin_table[index]; // 可用內差法改善精度問題

    }double sin_test()

    {

    double x=0, y=0;

    while(x<MAX) {

    y += sin(x*deg_to_rad);

    x+=STEP;

    }

    return y;

    }double sin_table_test()

    {

    double x=0, y=0;

    while(x<MAX) {

    y += sin_lookup(x);

    x+=STEP;

    }

    return y;

    }int main()

    {

    clock_t t1, t2;

    double y, y1, y2, delta;

    unsigned cnt=0;

    sin_init(); // 速度測試

    t1 = clock();

    y1=sin_test();

    t2 = clock();

    printf("sin , sum=%lf, elaspe: %ld\n", y1, t2-t1);

    t1 = clock();

    y2 = sin_table_test();

    t2 = clock();

    printf("sin_lookup , sum=%lf, elaspe: %ld\n", y2, t2-t1);

    system("pause");

    // 正確性測試

    y=0.0;

    while(y<MAX){

    delta = fabs( sin(y*deg_to_rad) - sin_lookup(y));

    if( delta > OUT_EPS) ++cnt, printf("deg:%lf, delta:%lf\n", y, delta);

    y+=STEP;

    }

    printf("delta > %lf has %d.\n", OUT_EPS, cnt);

    system("pause");

    return 0;

    }

    在精度方面有幾個可改善空間,一方面為使用內差法去求近似,

    但用內差法改善時,速度勢必會降慢;

    另一方面是加大 table 大小。若切成 1024 份,誤差只達 0.007 以下,

    若誤差要小於 0.001,則必須建 10000 左右大小之 table,

    且,速度並未比內建之 sin 函式還快!

    內建函式庫 (測過dev-c 與 vc) 之效能約為 1.5~2 倍。

    若是在「精度」與「速度」方面取捨,

    " 能用內建就用內建 ",數學函式的東西真的很難寫贏內附之函式

    (除非一些 "特例" 還有機會 )

    若堅持自己硬拼的話,建議先去 google "fast sin" 這種東西,

    這在國外論壇上很常看到、被討論

    ( 很多數學函式我硬拼過,大多拼不過 VC 開 O2,所以就不拼了 XD )

    若有問題,歡迎發問 :)

Still have questions? Get your answers by asking now.