テーブル化について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
サンタクロース

テーブル化について

#1

投稿記事 by サンタクロース » 14年前

こんばんは、私もPSPでシューティングを作っておりsin,cosのテーブル化を試みたのですが
どうも頭が固くて、とても初歩的なことでしょうけど回答お願いします
このソースは算術用関数sin()をSin()に置き換えて使うように作ったつもりです。
が、Sin()を呼び出すたびに初期化も行われているのでめちゃくちゃ時間がかかってしまうのです。
一般のテーブル化のように最初に一度だけ初期化を行いそれからSin()で数値の代入だけですむように
すればどうすればよいのでしょうか?
出来れば、龍神録のように○○.cppに~を追加。のように書いていただけるとありがたいです。
float Sin(int i){
    float Sin[361];
    if(i<0)i*=-1;//マイナス値にならないように
    if(i>360)i=i%360;//360度を超えたら360度以下する
    
    for(i=0; i<360; i++){
        
        Sin= sinf(PI2/360*i);
    }
    return Sin;
}
画像

たかぎ

Re:テーブル化について

#2

投稿記事 by たかぎ » 14年前

こんなのでどうでしょうか?

float Sin(int i){
struct initializer
{
float sin_table[361];
initializer()
{
for(i=0; i<360; i++){
sin_table= sinf(PI2/360*i);
}
}
};
static initializer init;

if(i<0)i*=-1;//マイナス値にならないように
if(i>360)i=i%360;//360度を超えたら360度以下する
return init.sin_table;
}

少年X

Re:テーブル化について

#3

投稿記事 by 少年X » 14年前

僕が関わったスレでないので広めるのは気がひけますけど書きます。
過去のNo:40384「三角関数のテーブル化」にある一周を1024度にした自作三角関数が載ってますよ。それを用いることによって処理速度は上がりました。しかし、そうすることによって数か所の書き換えが必要になったりするので頑張ってください。また、ftさんの話によれば、弾幕の計算以外で三角関数をテーブル化したところ処理が遅くなったとか・・・
まあ、いろいろと試してみるのがいいと思います。
あと、アドバイス的にことを少し・・・

・一気に改良するとどこでバグが発生したかわからない。
・PIではなく512となる。
・表示の際には度数法(1024度)から孤度法に変換する必要があります。

まあ、初心者がてこずった一例なので参考になればいいですけど^^

ft

Re:テーブル化について

#4

投稿記事 by ft » 14年前

if文は使わない方がいいと思います。

サンタクロース

Re:テーブル化について

#5

投稿記事 by サンタクロース » 14年前

こんばんわ、回答ありがとうございます。
自分でいろいろ考えてみたのですが、やはりsin_table[90]={0.000 0.・・・・}
という風に直接入れたほうがいいと思いまして進めていったのですが
詰まりました。externを使ってsin_cos.cppで宣言した0度から90度の値を含む配列を
boss_shotH.cppに渡したつもりでしたが、printfDxで配列の1つを表したけれど値は0.00でした。
externでは配列の値の受け渡しは出来ないのでしょうか?
あと、ftさんのいうとおりif文が多いので360度分の値を代入したほうがいいかもしれません
sin_cos.cpp--------
#include "GV.h"

  int Sin_table[91]={0    ,175  ,349  ,523  ,698  ,872  ,1045 ,1219 ,1392 ,1564 ,
                     1736 ,1908 ,2079 ,2250 ,2419 ,2588 ,2756 ,2924 ,3090 ,3256 ,
                     3420 ,3584 ,3746 ,3907 ,4067 ,4226 ,4384 ,4540 ,4695 ,4848 ,
                     5000 ,5150 ,5299 ,5446 ,5592 ,5736 ,5878 ,6018 ,6157 ,6293 ,
                     6428 ,6561 ,6691 ,6820 ,6947 ,7071 ,7193 ,7314 ,7431 ,7547 ,
                     7660 ,7771 ,7880 ,7986 ,8090 ,8192 ,8290 ,8387 ,8480 ,8572 ,
                     8660 ,8746 ,8829 ,8910 ,8988 ,9063 ,9135 ,9205 ,9272 ,9336 ,
                     9397 ,9455 ,9511 ,9563 ,9613 ,9659 ,9703 ,9744 ,9781 ,9816 ,
                     9848 ,9877 ,9903 ,9925 ,9945 ,9962 ,9976 ,9986 ,9994 ,9998 ,
                     10000};
 
  int Cos_table[91]={10000,9998 ,9994 ,9986 ,9976 ,9962 ,9945 ,9925 ,9903 ,9877 ,
                     9848 ,9816 ,9781 ,9744 ,9703 ,9659 ,9613 ,9563 ,9511 ,9455 ,
                     9397 ,9336 ,9272 ,9205 ,9135 ,9063 ,8988 ,8910 ,8829 ,8746 ,
                     8660 ,8572 ,8480 ,8387 ,8290 ,8192 ,8090 ,7986 ,7880 ,7771 ,
                     7660 ,7547 ,7431 ,7314 ,7193 ,7071 ,6947 ,6820 ,6691 ,6561 ,
                     6428 ,6293 ,6157 ,6018 ,5878 ,5736 ,5592 ,5446 ,5299 ,5150 ,
                     5000 ,4848 ,4695 ,4540 ,4384 ,4226 ,4067 ,3907 ,3746 ,3584 ,
                     3420 ,3256 ,3090 ,2924 ,2756 ,2588 ,2419 ,2250 ,2079 ,1908 ,
                     1736 ,1564 ,1392 ,1219 ,1045 ,872  ,698  ,523  ,349  ,175  ,
                     0     };//10の4乗しといてint型にする。使うとき1/10000する

int Sin(int kakudo){
     int sign=1;
     if(kakudo<0)kakudo=-kakudo;//角度が負の値なら正にする
     if(kakudo>360)kakudo=kakudo%360;//角度を360度以内に収める
     if(90 <kakudo && kakudo<=180)kakudo=180-kakudo;        //91度~180度なら
     if(180<kakudo && kakudo<=270)kakudo=kakudo-180,sign=-1;//181度~270度なら
     if(270<kakudo && kakudo<=360)kakudo=360-kakudo,sign=-1;//271度~360度なら
         return (sign*Sin_table[kakudo]);
}
    


int Cos(int kakudo){
     int sign=1;
     if(kakudo<0)kakudo=-kakudo;//角度が負の値なら正にする
     if(kakudo>360)kakudo=kakudo%360;//角度を360度以内に収める
     if(90 <kakudo && kakudo<=180)kakudo=180-kakudo;sign=-1;//91度~180度なら
     if(180<kakudo && kakudo<=270)kakudo=kakudo-180,sign=-1;//181度~270度なら
     if(270<kakudo && kakudo<=360)kakudo=360-kakudo;         //271度~360度なら
         return (sign*Cos_table[kakudo]);
}
    
boss_shotH.cpp--------
extern  int Sin_table[91];
extern  int Cos_table[91];
{sin()の代わりにSin()を1/10000を掛けて使用}

ft

Re:テーブル化について

#6

投稿記事 by ft » 14年前

色々なパターンで試していないのでどれが最適か分からないのですが、
以前サンタクロース氏が三角関数について本家掲示板にて聞いておりました回答がif文を使ってなかったので
とても良いものと考えて用いています。
現在は過去ログにありますが

『日時: 2009/10/25 23:20
名前: 憂煉

・・・すいません。ちょっと意味不明な気がします。
>サイン、コサインのあたいをfor()文に対応したマクロ定義?の書き方が分からないです。

とりあえずこんなのはどうでしょうか

float sincos[360];

void initSincos()
{
int i;
for(i = 0;i < 360;++i)
{
sincos = sin(i * PI / 180);
}
}

#define SIN(KAKUDO) (sincos[KAKUDO % 360])
#define COS(KAKUDO) (sincos[(KAKUDO + 90) % 360])

initSincosで配列を初期化し、SIN、COSの関数マクロで値を取得します。』

見覚えありますでしょうか?
この例では1周を360等分していますが、私は一周1024等分にして%360をビット演算子「&」で計算してます。
これでif文を使うことなく、値はビット演算で探し出せます。
またテーブル初期化と参照部分は分離されているので混同されにくいと思われます。 画像

non

Re:テーブル化について

#7

投稿記事 by non » 14年前

たかぎさんのプログラムがいいと思うけど、環境で問題があるなら
こんなのではいかがですか。
#define PI 3.14159265f
float Sin(int deg)
{
    int i;
    static int sw=0;
    static float sin_table[360]; 
    if(sw==0){
        for(i=0; i<360; i++)
            sin_table= sin(PI/180*i);
        sw=1;
    }    
    if(deg<0) deg*=-1;//マイナス値にならないように 
    if(deg>360)deg=deg%360;//360度を超えたら360度以下する     
    return sin_table[deg]; 
}

fatens

Re:テーブル化について

#8

投稿記事 by fatens » 14年前

>float Sin[361];
360°= 0°なので要素数は0~359の360個で良いです。

>if(i<0)i*=-1;//マイナス値にならないように
これだけだと例えば、sin(-90°) = sin90°になってしまいます。

>if(i>360)i=i%360;//360度を超えたら360度以下する
比較をなるべく少なくするのであれば常にi=i%360としても良いと思います。

Cなら、
float Sin(int deg)
{
    const static float sin_table[/url] = {
        0.0000000f, 0.0174524f, 0.034899f, 0.0523359f, 0.0697564f,
        //以下略
    };

    if (deg < 0)
        return -sin_table[-deg % 360];

    return sin_table[deg % 360];
}

float Cos(int deg)
{
    return Sin(deg + 90);    //sinとcosは90°ずれている
}
C++なら、たかぎさんのような方法でsin_tableを初期化する。

というのはどうでしょう(未検証)

たかぎ

Re:テーブル化について

#9

投稿記事 by たかぎ » 14年前

私の方法で問題が出るとすれば、マルチスレッドの場合か、標準準拠度が非常に低いC++処理系(GCCなら、よほど古いバージョンでない限り問題ないでしょう)か、Cの場合だけです。
まあ、内部的には条件分岐が発生していますので、そのオーバーヘッドが問題になるのであれば、関数の外に追い出すしかありません。

kazuoni

Re:テーブル化について

#10

投稿記事 by kazuoni » 14年前

テーブル化はいろいろ工夫しがいがありますよね。
以前Justyさんからのアドバイスをいただいたものを実現してみました。
もう少し精度がほしい場合用ですかね。

自分の場合は、nonさんよりはメモリを約2.8倍食いますが、
その分精度が上がります。(360→65536)
ただ、シューティングにはこんな精度いらないですかね。

参考までに。

#追記
説明を書いていませんでした。
0~2PIを
0~65535で表現しただけです。
ぱっとみ「へ?」って思うかもしれませんが、結構便利です。
特に正規化とかは。
っというか、これは正規化のためのものである気がしますが^^;

#さらに追記
psp開発の環境でコンパイルしていませんので良くわかりませんが、
M_PIが使えないかもしれないです。
(たしかgccだった気がするので使えるのかな・・・?) 画像

サンタクロース

Re:テーブル化について

#11

投稿記事 by サンタクロース » 14年前

皆さん、いろいろな回答ありがとうございます。
テーブル化とひとくちに言ってもさまざまな方法がありますね。
>>ftさん 過去ログだったのですね。私もその記事を参考にしようと思ったのですが
どうにも見つからず削除されてしまったのかな?と思いました。
みなさんのソースはとても参考になりました。

結果としては、あらかじめsinとcosの360度分の値を配列に渡しておき関数で呼び出すことにしました
毎回360個のint型を用意していて馬鹿みたいかも知れませんが一応、自分もまだまだ
初心者ですので、今のところは処理落ち云々にこだわり過ぎないでいこうと思います。

>>ftさん(zaneさん?)も初心者XさんもPSP本家のほうでよく見かけます。
PSPで移植、これからもがんばっていきましょう^^ 画像

閉鎖

“C言語何でも質問掲示板” へ戻る