省メモリと動作速度

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
COFE
記事: 97
登録日時: 13年前

省メモリと動作速度

#1

投稿記事 by COFE » 12年前

今PSPに龍神録を移植しています
やはりクオリティの低いものですが、オリジナルの弾幕も2つほど動作させ、タイトルも作り5回ぴちゅるとゲームオーバーという概念も作ってなんとかゲームらしくまとまりました
ただ、PSPで動作させているためやっぱりFPSが30~40くらいになってしまいます(性格には計っていません、だいたいこんなもんかなって奴です)
ちなみにPSPのスペックはCPUが333MHz、メモリ32MB(うちカーネルが8MBを占有エリアとして確保)です(出典wiki)

メモリに余裕があんまりないため、いろいろ調べているとmallocという関数を見つけました
①あれってポインタを宣言して、freeにはめると、参照先のメモリが全部解放されるっていう考えでいいのでしょうか?

また

コード:

void b(){
     printf("hello");
     return;
}
void a(){
     b();
     return;
}
int main(){
     a();
     return 0;
}
これと

コード:

int main(){
     printf("hello");
     return 0;
}
②これだとやっぱり下のほうがより高速になりますか?

後半なんかPSP関係なくなってきちゃいました^^;

③無駄をいろいろ削ぐテクニックはmallocの他に何がありますか?

よろしくお願いします

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#2

投稿記事 by softya(ソフト屋) » 12年前

省メモリにするには色々方法がありますが、まず画像の解像度や色数を減らせば大幅な省メモリになります。
PSP開発環境に詳しくないので、どんな色数のデータが最適なのかを調べてみてください。

あとmallocですがPSP開発環境では使えるのでしょうか?まずそこを確認してください。
それとmallocしてfreeで解放するメモリは必要ないから解放するのであって毎フレーム確保・解放なんて繰り返したら却って遅くなります。
利用できる場面をよく考えてみてください。龍神録には殆ど無いはずです。
ちなみにC++ならnew、deleteを使うようにしてくださいね。
COFE さんが書きました:②これだとやっぱり下のほうがより高速になりますか?
YESです。関数呼び出しは少ない方が早くなりますが、プログラムが読み辛くなるのなら無闇に減らすべきではありません。
それよりは他の工夫で早くなることも多いです。
特にPSPはパソコンと違い浮動小数点型であるdoubleやsin/cos関数が激烈のに遅いはずなので、そこを工夫したほうが良いでしょう。

「ちく のPSPゲーム移植講座!」
http://www.geocities.jp/z_gundam_tanosi ... Kouza.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#3

投稿記事 by COFE » 12年前

早速の解答ありがとうございます
PSPでもmallocは使えます、使いたかったタイミングはタイトル画面がそこそこ容量を食うデザインだったので
タイトルの画像ロード

タイトルの場面

ゲーム開始時にタイトルの画像をfree

こうやって仕様かなと思ってました、タイトルの画像をゲーム本編で使うことはないので

教えていただいたURLを参考にしようと思います、ありがとうございました

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#4

投稿記事 by COFE » 12年前

と、すいません
教えていただいたページにテーブル化と書いてあったのですがこれはどういう意味ですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#5

投稿記事 by softya(ソフト屋) » 12年前

タイトル画面などの画像の解放はDXLIBポータブルでも同じだと思いますがDeleteGraph()で開放してください。
freeでは開放できませんよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#6

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:と、すいません
教えていただいたページにテーブル化と書いてあったのですがこれはどういう意味ですか?
これは毎回sin/cos関数を呼ぶと遅くなるので、sin/cos関数の結果を一度単位などで360度分の配列にして持っておくことで毎回sin/cos関数を呼ぶことを避けるテクニックです。[補足]実際には90度分のsinテーブルで360度cosまでサポート可能です。

過去ログが参考になるでしょう。
「三角関数のテーブル化 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=6079
「テーブル化について • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=4588
「弾幕計算の高速化 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3&t=4521
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#7

投稿記事 by COFE » 12年前

ない頭で必死に考えた結果テーブル化とは
#define sin(KAZU) mysin[KAZU];

float mysin[90]={0 , 0.0175 , 0.0349,};
float mycos[90]={1 , 0.9998 , 0,9994 ,};

こういうものだと思ったんですがコレって合ってますか?
あと過去ログの方でdixqさんが「1度づつでは足りない、その10倍は欲しい」と言われていましたが
これっはどういう意味なのでしょうか?

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#8

投稿記事 by COFE » 12年前

と思いましたが上に出したテーブル化は正解じゃありませんね
sin(PI/180*i)と龍神録でよく書きますが、()の中がfloatの小数だからintにキャストすると計算が大雑把になっちゃいますね
dixqさんが「その10倍は欲しい」といった理由が分かりました

ということは

コード:

#define sin(KAZU) mysin[KAZU];

float mysin[901]
float mycos[901]

for(int i=0;i<900;i++){
     mysin[i]=sin(180/PI*i);
}

for(){cos}//省略
こんな感じかな?と思いました
合ってますかね?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#9

投稿記事 by softya(ソフト屋) » 12年前

実際にはcosはsinの位相の違う波ですからmysinだけで事足りますよ。
省メモリなら、mycosは略するべきです。
COFE さんが書きました:dixqさんが「その10倍は欲しい」といった理由が分かりました
0.1度づつという意味なら宣言はmysin[901]であってますが、計算が違います。
まず、0.1度単位に変換します。
double angle = 0.1 * (double)i;
次にラジアン角に変換します。
double rad = PI * (180.0 / angle);

sin(rad);
です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

xxx
記事: 26
登録日時: 13年前

Re: 省メモリと動作速度

#10

投稿記事 by xxx » 12年前

vfpu使うか360度を2の累乗で分割してintで計算すればかなり速くなります

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#11

投稿記事 by softya(ソフト屋) » 12年前

確か過去に話題になったなぁと思い検索してみました。

「処理落ちの軽減についてと、発射に時間差のある弾の描画順位について • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?f=3 ... fpu#p38818

言えることは、PSPで高速化するためにはPSPのCPUクセ・PSPハードウェアのクセ・C言語などの総合的な知識が必要です。つまり、パソコンで龍神録を高速化するよりも高度なテクニックが必要になってきます。色々とチャレンジして知識を身に付けてくださいね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#12

投稿記事 by COFE » 12年前

今までラジアンって言うものの意味がよくわかってなかったんですが、もしかしてPIで角度を表す方法ですか?
あと

コード:

#define sin(KAZU) mysin[KAZU];
float mysin[901]
 
for(int i=0;i<900;i++){
     mysin[i]=sin(180/PI*i*0.1);
}
さっきのソースをこう書けってことですか?(10倍にしてんだから1/10で求めるのは当たり前でしたね)

もう一つ
>実際にはcosはsinの位相の違う波ですからmysinだけで事足りますよ。
>省メモリなら、mycosは略するべきです。

これってどういう事ですか?sinだけでcosも分かっちゃうんですか?

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 省メモリと動作速度

#13

投稿記事 by ISLe » 12年前

手前味噌ですが、参考になりますでしょうか。
三角関数のテーブル化に加えて、浮動小数点数を使わないようにできます。
ゲーム向け固定小数点数ライブラリ:ISLeのビデオゲーム工房
自作プログラムに組み込む用途であれば自由に使っていただいて構いません。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#14

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:今までラジアンって言うものの意味がよくわかってなかったんですが、もしかしてPIで角度を表す方法ですか?
ラジアン角=弧度法と言いますが、2*PIが360度と言う意味になります。
「ラジアン - Wikipedia」
http://ja.wikipedia.org/wiki/%E3%83%A9% ... 2%E3%83%B3
なので、
sin(180/PI*i*0.1);
だと
90度の時にsin(180/PI*900*0.1)となりsin((180*90)/PI)ですから計算が変ですよ。
式を再確認してみてください。
COFE さんが書きました:これってどういう事ですか?sinだけでcosも分かっちゃうんですか?
「三角関数のグラフ」
http://www.crossroad.jp/mathnavi/math-i ... urafu.html
これで分かるでしょうか?

cosとsinは同じ波形で、sinから90度ずれているだけです。
なので、cosを90度ずらすとsinの計算でcosの値を求めることが出来ます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#15

投稿記事 by COFE » 12年前

>roxion1377さん
>ISLe さん

ごめんなさい、レベルが高すぎてわけわかめです

>softyaさん

コード:

#define sin(KAZU) mysin[KAZU];
float mysin[901]
 
for(int i=0;i<900;i++){
     mysin[i]=sin(PI/180*i*0.1);
}
こうですか?

>cosを90度ずらすとsinの計算でcosの値を求めることが出来ます。

ということは

コード:

for(i=0;i<900;i++){
     mycos[i]=mysin[i]+PI/2;//90度=PI/2
}
コレでいいってことなんでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#16

投稿記事 by softya(ソフト屋) » 12年前

>こうですか?

そうです。

>mycos=mysin+PI/2;//90度=PI/2

それは、配列の添字やら弧度法やらsinの計算後の値やらごっちゃになっています。
それにメモリ節約で、mycosテーブルを無くす話をしていたはずですよ。mycosテーブルを初期化する必要はないんです。

例としてテーブルから値を取り出す関数
float tableSin( float 度数法の角度 )
と言う関数を作ったら

コード:

float tableCos( float 度数法の角度 ) {
 return tableSin( 度数法の角度+90 );
}
と言う関数を作ればmycosテーブル不要ですって話です。

あと最終的には、roxion1377さんやISLe さんの話を理解しないと東方並の弾幕密度の弾幕シューティングは速度的に厳しいかも知れません。
PSPで組んだことがないでの断言はできませんが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 省メモリと動作速度

#17

投稿記事 by ISLe » 12年前

COFE さんが書きました:ごめんなさい、レベルが高すぎてわけわかめです
基本的にfloatで宣言されているところをfixedに変えるだけで使えるようにはしてあるのですが。
付属サンプルの浮動小数点数版と固定小数点数版を比べてみてください。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#18

投稿記事 by COFE » 12年前

>softyaさん
本来の目的をすっかり忘れていました

コード:

float tableCos( float 度数法の角度 ) {
     return tableSin( 度数法の角度+90 );
}
度数法って360度で表すやつですよね?なんでラジアンを使わないんですか?

コード:

//iniでやる処理
float mysin[901]
for(int i=0;i<900;i++){
     mysin[i]=sin(PI/180*i*0.1);
}

//sin,cosの代わりに使う関数
tableSin(float kakudo){
     return mysin[(int)kakudo];
}

tableCos(float kakudo){
     return mysin(kakudo+PI/2);
}
最終的にこんな感じでまとまったんですけどこれじゃダメですかね?

>あと最終的には、roxion1377さんやISLe さんの話を理解しないと東方並の弾幕密度の弾幕シューティングは速度的に厳しいかも知れません。
大丈夫です。学校の課題とかそういうわけでもないので。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#19

投稿記事 by softya(ソフト屋) » 12年前

>度数法って360度で表すやつですよね?なんでラジアンを使わないんですか?

私のは参考に書いただけなのでラジアン角にしても全然かまいませんよ。

>return mysin[(int)kakudo];
聞く前に試されましたか?

(1)kakudoは度数法角度でしょうか?それともラジアン角?
(2)添字が0~900の範囲で0度から90度の設計になっているので、そこから外れるとエラーです。過去ログを再確認を。-720や1080度が入力されても大丈夫なように補正の計算が必要です。
(3)mysin(kakudo+PI/2);を見る限りラジアン角なんですか? でも、小数点の値で配列はアクセス出来ませんよ。cos(90度)の値は0が返りますか?

良く考えて、まず自分で動かしてみてください。
そして関数をいかにテストするかテスト法を考えて、テストのためのソースコードも一緒に考えましょう。
ここで聞く前に試したほうが試す前に聞くよりも問題点を自分で確認してから聞いたほうが、より深く学ぶことが出来ます。
ぜひ、実践してみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#20

投稿記事 by COFE » 12年前

すいません、こんな人間で
sin,cos自体もよく理解できていないようです
その上に弧度法も混ざってくるからややこしくて……

過去ログから拾ってきたものを改造しました

コード:

#define sin(KAKUDO) (mysin[KAKUDO % 360]) 
#define cos(KAKUDO) (mysin[(KAKUDO + 90) % 360]) 
float mysin[360]; 

for(int i = 0;i < 360;++i) {
      mysin[i] = sin(i * PI / 180); 
}
どう見ても弧度法の角度を渡さにゃならん関数ですよね(関数じゃないけど)
これをどうにかラジアン角に対応させたいんですがどうしましょう

#define sin(KAKUDO) (mysin[(int)(KAKUDO % PI/180)])
#define cos(KAKUDO) (mysin[(int)((KAKUDO + 90) % PI/180)])

こうやってしたら角度がPI(3.141592)の時には弧度法で180度の配列が呼ばれていいかんじだと思うんですが

蛇足になりますが今visual C++2008がしょっちゅうフリーズします
visual C++2010はだいぶ前からフリーズ続きです
Borland C++ compilerはlink32.exeが実行できないと言われます
学習用C言語開発環境(EasyIDEC)は表面的にはコンパイルに成功しているもののexeを走らせると起動できません
cygwinをインストールしていますが時間が死ぬほどかかっています、windows用のGCCは何故かダウンロードに失敗します
PSPSDKはちゃんとビルド出来ますが、PSPが今行方不明です
今visual C++2008をインストールしなおしています

それとさっきからしきりに90度の時のことを~と言われるのは何故ですか?
90度の時はなんかマズイことでもあるんでしょうか?

xxx
記事: 26
登録日時: 13年前

Re: 省メモリと動作速度

#21

投稿記事 by xxx » 12年前

#define sin(KAKUDO) (mysin[KAKUDO % 360])
KAKUDOが負の数の場合%の動作はどうでしたっけ.
負の数の時は正の数に直さなければまずかった記憶があります
KAKUDOもintにキャストしてあげたほうがいいと思います
書き忘れてましたがfastmath.hをインクルードしてある程度高速なsinfやcosfを使ってもいいと思いますよ
(sin,cosを考えるよりもループの回数を気にしたり,計算以外の処理を減らすことを考えたほうがいい気もする.

>cygwinをインストールしていますが時間が死ぬほどかかっています
psptoolchainはps2dev?が落ちてるので海外のフォーラムで拾うしか無いですね

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#22

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:それとさっきからしきりに90度の時のことを~と言われるのは何故ですか?
90度の時はなんかマズイことでもあるんでしょうか?
元のmysin=sin(PI/180*i*0.1);でテーブル代入している値を確認してみてください。90度以降の値はありますか?
新しいfloat mysin[360]; は有るみたいですが、実際には90度までの値を上手く使うことで360度分の値を作る事とが出来ます。
これもsin波形の特性をうまく使った省メモリです。過去ログで90度までのテーブルにする話があったので、そういう設計で行くのかと思ってました。
それと0.1度単位ではなくなってますよ。

COFE さんが書きました: #define sin(KAKUDO) (mysin[(int)(KAKUDO % PI/180)])
#define cos(KAKUDO) (mysin[(int)((KAKUDO + 90) % PI/180)])


%で計算できる余りの計算は整数のみです。浮動小数点が混合された計算で使ってはいけません。
それと整数⇔浮動小数点の変換は結構負荷がでかいので高速化を図るなら避けるべき行為です。
なにか計算で浮動小数点と整数の変換を暗黙変換に任せっぱなし感がありますので、きっちり明示的にキャストして書いてみてください。
それと名前はsinで関数名とかぶるのでNGです。

過去ログの内容をよく見て理解してみてくださいね。今言った話題は必ず出ているはずです。

[追記]
COFE さんが書きました: 蛇足になりますが今visual C++2008がしょっちゅうフリーズします
visual C++2010はだいぶ前からフリーズ続きです
Borland C++ compilerはlink32.exeが実行できないと言われます
学習用C言語開発環境(EasyIDEC)は表面的にはコンパイルに成功しているもののexeを走らせると起動できません
cygwinをインストールしていますが時間が死ぬほどかかっています、windows用のGCCは何故かダウンロードに失敗します
PSPSDKはちゃんとビルド出来ますが、PSPが今行方不明です


なんかOSと言うかレジストリや環境変数等がやばそうな感じですね。
数年同じOSを使っているならOSを再インストールしたほうが良いかも知れません。
あるいはメモリに不良がある可能性もありますが。
コンパイラ以外のソフトでも不具合がでるならメモリを疑ってもよいでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#23

投稿記事 by COFE » 12年前

私はどうすればいいのでしょうか?
アレはダメこれはダメ、softyaさんはきっと私のことを考えて私のためになるように導いてくれているのだと思いますが、私の目的はそれではありません
私のやりたいことは
「sin cos関数で呼び出している値を現在のソースに手を加えること無くテーブル化で高速化したい」
ただこれだけです
例えばsin(PI)と呼び出されているものには……
今いいこと思いつきました

コード:

mysin[31411593];
for(int i=0;i<31411592;i++){
     mysin[i]=sin(i/10000000);
}

Sin(float kakudo){
     return mysin[kakudo*10000000]
}
さあ、今度こそどうでしょう?

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 省メモリと動作速度

#24

投稿記事 by ISLe » 12年前

COFE さんが書きました:今いいこと思いつきました

コード:

mysin[31411593];
floatですよね。
テーブルの大きさが120MBほどになるようですが。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#25

投稿記事 by COFE » 12年前

ごめんなさい、眠けのノリでどうでもいいことを考えていました
忘れてください

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#26

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:アレはダメこれはダメ、softyaさんはきっと私のことを考えて私のためになるように導いてくれているのだと思いますが、私の目的はそれではありません
私のやりたいことは
「sin cos関数で呼び出している値を現在のソースに手を加えること無くテーブル化で高速化したい」
ただこれだけです
最終的に省メモリと高速化を実現したいんだと思ってましたが違うのでしょうか?
あと、何度か説明したように元の龍神録のint/float/doubleなど混合されたコードのままでは全体的な高速化は難しいと思います。
今回は、とりあえず全体的な高速化は置いておいて部分的なsin/cosの高速化を行うのを主目的とすると言うことでよろしいですか?

で、混乱しているようですので、まずちゃんと設計しましょう。
(1)sin/cosの引数はラジアン角でfloat値である。戻り値も同様にfloatである。
(2)テーブルの分解能は1/2*PI(90度)の1/900単位である。→変えても良いですよ。
(3)テーブルはメモリ節約のため0~1/2*PIの範囲の値しか持たない。他の角度はテーブルを使って計算で求める。
(4)-10*PIやら+20*PIやら0~2*PI(360度)の範囲外のラジアン角にも対応している。
(5)sin/cosの関数名は本来のものと多重宣言になるので別のものに置き換える。
これらの中で(3)とか自分的に難しいと感じたら除外して良いです。
16KB→4KBほどの差ですからね。

最後に、私はCFW対応のPSPを持っていないので導くことしか出来ません。動作検証するのは、COFEさんですからね。
なのでCOFEさんがちゃんと理解していないと速度の検査やバグなど動作検証もできないわけですし、ボトルネックを捜す方法や改善方法も自分で検討しないといけないわけです。
なので慌てず自分の出来る範囲で少しづつ進めて行ってください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#27

投稿記事 by COFE » 12年前

優しく諭していただきありがとうございます
もう省メモリとかどっか行っちゃいましたが、意地でもテーブル化は完成させたいです
とりあえず

(1)sin/cosの引数はラジアン角でfloat値である。戻り値も同様にfloatである。
>眠気のノリで作った奴はだめということですね
(2)テーブルの分解能は1/2*PI(90度)の1/900単位である。→変えても良いですよ。
>まずは90度の範囲でくろうと思います
(3)テーブルはメモリ節約のため0~1/2*PIの範囲の値しか持たない。他の角度はテーブルを使って計算で求める。
>多分理解
(4)-10*PIやら+20*PIやら0~2*PI(360度)の範囲外のラジアン角にも対応している。
>returnの前に何かしらの判定をおけばいい?
(5)sin/cosの関数名は本来のものと多重宣言になるので別のものに置き換える。
>Sinにします

コード:

float mysin[91]
for(int i=0;i<90;i++){
	mysin[i]=sin(PI/90*i);
}
float Sin(float rad){
	while(1){
		if(rad>PI && rad<=2PI){
			rad=rad-PI;
			return mysin[PI/2/rad];
		}
		else if(rad>2PI){
			rad=rad-PI;
		}
	}
}
とりあえずsinの場合のみの関数をつくってみたのですが、値の返し方がこれであっているのかわかりません
ラジアンを弧度法に変換する関数も確かmath.hにありましたが、これを使ったら本末転倒ですよね

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#28

投稿記事 by softya(ソフト屋) » 12年前

それではテーマをsin/cosのテーブル化に絞ります。

コード:

float mysin[91]
for(int i=0;i<90;i++){
    mysin[i]=sin(PI/90*i);
}
ラジアン角の変換が間違っています。
(1/2)*PIが90度です。

sin波形の解釈に間違いがあります。下記サイトのグラフを見てください。
http://www8.plala.or.jp/ap2/suugaku/san ... html#graph
テーブルは90度までしか無いので波形はπ/2までのデータしか参照できません。
なので91度から180度、181度から270度、271度から360度はテーブルを元に別々の値を計算しなくてはいけません。
ややこしいので、とりあえずラジアン角→度数変換します。
int kakudo = (int)(rad * 180.0 / PI);
このkakudo が0から360度の範囲になるように補正します(後述)。
でとりあえず、91度から180度からの範囲の例を示します。

コード:

if( (90<kakudo) && (kakudo<=180) ) {
 return mysin[kakudo-90];
}
と書くと実は間違いです。
正しくは、

コード:

if( (90<kakudo) && (kakudo<=180) ) {
 return mysin[180-kakudo];
}
となります。波形をよく見て考えてみてください。

で、0~360度の範囲に収める方法ですが、whileループしたら高速化の意味がありません。計算しましょう。
if( kakudo > 360 ) kakudo = kakudo % 360;
if( kakudo < 0 ) さて、どう計算しますか?考えてみてください。

[追記]
ついでにテスト環境をDXライブラリとVC++で作ってみましょうか。
参考サイトのグラフのように-360度から720度までDrawPixelでsin波をプロットしてみてください。
まずは普通のsin関数で色は白、自作sin関数の色は赤でプロットします。
これでずれていたら一発でわかります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#29

投稿記事 by COFE » 12年前

弧度法ではなくラジアンで引数を渡したいです

コード:

float mysin[91]
for(int i=0;i<90;i++){
	mysin[i]=sin(PI/90*i);
}
float Sin(float rad){
	int a=-1;
	if(rad<0) rad=rad*a;
	if(rad>PI && rad<=2PI){
		rad=rad%(PI/2);
		return mysin[PI/2/rad];
	}
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#30

投稿記事 by softya(ソフト屋) » 12年前

慌てないでください。Sin関数の引数がラジアン角であれば良いのでSin関数の内部は、どう扱っても良いと言うのを理解しておいてください。
本当にラジアン角のままSin関数の内部まで処理することは便利なのでしょうか?
Sin関数の内部では配列が度数法で格納されているので、どちらにしろテーブルのアクセスはint型の度数法で行う必要があります。どうせ度数法にするのならPSPで高速なint型を多用しようと考えたので、まっさきにint型の度数法に変換する処理を書かせてもらいました。
あとrad=rad%(PI/2);は整数と浮動小数点の理解が怪しいです。%は整数演算ですので思った答えが得られませんよ。このトピック内で何度も整数と浮動小数点を混ぜてはいけないと書いてますが、信じられないなら実際にテストプログラムを書いて試してみてください。

それと私の提案したDrawPixel()のテストプログラムを作れば簡単に確認できますので、ご自分で作った関数が上手く作れているか実際に確認を行ってください。
このプログラムは動作テストしたとは思えません。

コード:

float mysin[91]
for(int i=0;i<90;i++){
    mysin[i]=sin(PI/90*i);
}
float Sin(float rad){
    int a=-1;
    if(rad<0) rad=rad*a;
    if(rad>PI && rad<=2PI){
        rad=rad%(PI/2);
        return mysin[PI/2/rad];
    }
}
DrawPixel()のテストプログラムで、そんなに難しい提案をしたつもりはありませんが分からないことがあったら聞いてください。

ちなみに弧度法とラジアンは同じ意味ですよ。

[補足]
私はCOFEさんに自分で理解してプログラム組んで欲しいのです。
パソコンに比べて貧弱なハードであるPSPで組むというのは、それはそれは大変な事なので一歩一歩理解して進むしか有りません。
苦労して覚えたことは、応用力にもなります。がんばってください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#31

投稿記事 by COFE » 12年前

すいません、%の決まりはすっかり忘れていました

それとDXライブラリを使わないで試す方法はありませんか?
今パソコンが調子悪いので知り合いに見てもらっているところです
しばらく帰ってこない予定なのであんまりスペックの良くないパソコンで今書いています
プロンプトに出すやつでsin,cosとかは……無理ですよね

あと私が自作のSin関数の引数をラジアンでやりたいとこだわる理由は、ソースコードに手を加えたくないからです
今でも理解力はありませんが、龍神録の館で弾を飛ばすのにsin,cosを使っていたので三角関数を必死に勉強しました
sinθだのcosθだのいみわからない用語はありましたが、一応龍神録の玉を飛ばす部分が理解できるようになりました
ご指摘の通り用語についても詳しく一から学んだわけではないので曖昧です
ただでさえ今でも頭でグチャグチャになっている360度=2PIがよりややこしくなって訳分からんくなりそうで怖いです
ここから自作の龍神録モドキのsin,cosを私が書き直すと間違いなく100%バグが出ます

どうにか現在のソースコードのsin()の部分をSin()に置き換えるだけで処理が高速に成るようにしたいと甘いこと考えてます
何とかなりませんでしょうか?

とここまで書きましたが、よくよくsoftyaさんの意見を見直すとPSPではint型のほうが計算が早いのですね
だったら昨日思いついた

コード:

mysin[31411593];
for(int i=0;i<31411592;i++){
     mysin[i]=sin(i/10000000);
}
 
Sin(float kakudo){
     return mysin[kakudo*10000000]
}
これを改良してくのはsoftyaさん的にはダメですかね?
なんでもキャッシュが120MBになると昨日ISLeさんに教えてもらったのですが
配列を1/10にしたらこれでもいいですかね?

ちなみにBorland C++ compilerを今使ってるパソコンにインストールしてるところです

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#32

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:すいません、%の決まりはすっかり忘れていました
それとDXライブラリを使わないで試す方法はありませんか?
今パソコンが調子悪いので知り合いに見てもらっているところです
しばらく帰ってこない予定なのであんまりスペックの良くないパソコンで今書いています
プロンプトに出すやつでsin,cosとかは……無理ですよね
コマンドプロンプトでも数値でなら確認できますよ。sin計算の値とSinの値を並べてみれば正しいかは検証出来ますよね。
COFE さんが書きました: あと私が自作のSin関数の引数をラジアンでやりたいとこだわる理由は、ソースコードに手を加えたくないからです
今でも理解力はありませんが、龍神録の館で弾を飛ばすのにsin,cosを使っていたので三角関数を必死に勉強しました
sinθだのcosθだのいみわからない用語はありましたが、一応龍神録の玉を飛ばす部分が理解できるようになりました
ご指摘の通り用語についても詳しく一から学んだわけではないので曖昧です
ただでさえ今でも頭でグチャグチャになっている360度=2PIがよりややこしくなって訳分からんくなりそうで怖いです
ここから自作の龍神録モドキのsin,cosを私が書き直すと間違いなく100%バグが出ます

どうにか現在のソースコードのsin()の部分をSin()に置き換えるだけで処理が高速に成るようにしたいと甘いこと考えてます
何とかなりませんでしょうか?
私の提案したのは外部的にはラジアン角のままですよ。内部を度数法で処理しているだけです。
なのでsin→Sinに置き換えるだけで使えます。
なので、落ち着いて私の説明をよく読み考えてみてください。引数を度数法に変えるとは一言も書いていません。
COFE さんが書きました: これを改良してくのはsoftyaさん的にはダメですかね?
なんでもキャッシュが120MBになると昨日ISLeさんに教えてもらったのですが
配列を1/10にしたらこれでもいいですかね?
PSPのアプリ用のメモリって確か24MBぐらいしか無いんですよね?
そのうち120MB/10=12MBもsinだけで使ったらメモリが絶対足らなくなりますよ。
これも何度も書きますが、落ち着いて考えてみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#33

投稿記事 by COFE » 12年前

すいません、今から落ち着いてこのトピックを1から見なおします
その上でもう一度疑問点などをまとめてみます

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#34

投稿記事 by softya(ソフト屋) » 12年前

No: 16で度数法の話は出てますが、その時にラジアン角が良いとのことだったので、その後はラジアン角で処理する前提で話を書いているはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

xxx
記事: 26
登録日時: 13年前

Re: 省メモリと動作速度

#35

投稿記事 by xxx » 12年前

>sin(i/10000000);
10000000.0にしなきゃまずいですね

PSPで計算するときintとfloatの速度はそんなに変わらなかった気がします
あとテーブル化にこだわる理由は何ででしょう?fastmathがあるのに.

具体的な数値は出せませんがvfpuのほうが高速だった気がします.
http://trac2.assembla.com/oslibmod/brow ... s.c?rev=25
vfpu_sincos(angle,&sin_val,&cos_val);
のように使えば一度にsin,cosが計算できます

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#36

投稿記事 by COFE » 12年前

>roxion1377さん
他の方法も教えていただきありがとうございます
VFPUにも興味がありましたのでまた今度試してみます

ですがもう私の頭の中はsinのテーブル化のみです
せっかく教えてもらったのにすいません

もうここはsinテーブル専用トピックということにしといてください

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#37

投稿記事 by softya(ソフト屋) » 12年前

調べてみました。
floatとintは同速のようですね。失礼しました。
ただ、float⇔intの型変換は激烈に遅いのでできるだけ避けて、暗黙の型変換を起こさないように細心の注意をはらう必要があります。

コード:

    int a=-1;
    if(rad<0) rad=rad*a;
ここらへんとか無頓着に暗黙の型変換を使いすぎています。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#38

投稿記事 by COFE » 12年前

もう本当すいません
プログラミングに興味を持った頃にはcore 2 duoとか出ていた頃で処理が重くて困るとかいうことは今まで無かったもので……
使う型といえばずっとintとdoubleでした

>int a=-1;
>if(rad<0) rad=rad*a;
>ここらへんとか無頓着に暗黙の型変換を使いすぎています。

どうやったら-のデータを+に直せますか?
コレばっかりは上に出して注意された奴しか思いつかないです

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#39

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:もう本当すいません
プログラミングに興味を持った頃にはcore 2 duoとか出ていた頃で処理が重くて困るとかいうことは今まで無かったもので……
使う型といえばずっとintとdoubleでした

>int a=-1;
>if(rad<0) rad=rad*a;
>ここらへんとか無頓着に暗黙の型変換を使いすぎています。

どうやったら-のデータを+に直せますか?
コレばっかりは上に出して注意された奴しか思いつかないです
rad=-rad;
ですよ。マイナス単項演算子です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#40

投稿記事 by COFE » 12年前

改めてhttp://www.crossroad.jp/mathnavi/math-ii/sanka ... のサイトを見たところ
まあなんと分かりやすいことでしょう
今まで分からなかった所が綺麗に吹き飛びました

とりあえず私の作りたいものを整理すると
float mysin[91]と宣言する
initで初期化
Sin関数をfloatのラジアンで呼び出し、それをラジアンから度数法の角度に変換する
例えば引数が0.0174524だったときはそれを何とかして1度に変換するです
コレを目指して頑張っています

[追記]
http://detail.chiebukuro.yahoo.co.jp/qa ... q137568028
ここで弧度法と度数法変換する方法書いてありました
ラジアン→度数法の場合は180/πをかけるといいらしいです
コレを踏まえて

コード:

#define PI 3.1415926f
float mysin[91];
IniSin();//省略

float Sin(float rad){
     int kakudo;
     kakudo=rad*180/PI;

     if(kakudo<0){
          kakudo=-kakudo;
     }
     if(kakudo>90){
          kakudo=kakudo%90;
     }
     return mysin[kakudo];
}

と今までのことを踏まえてここまで書きましたが

コード:

kakudo=rad*180/PI;
あきらかにこれsoftyaさんなめきった書き方です、やり直します



とまあこんな感じで自分の日記帳みたいに書いて頭を整理していたわけですが、やっぱりできていないのはfloat←intに変換したくなっちゃうことだと思います
どうあがいてもint=float;こういうコードになっちゃいます
さっきのコードでは多分小数点以下が全部0になると思いますが、その場合でもintの変換は処理が遅いのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#41

投稿記事 by softya(ソフト屋) » 12年前

float⇔intの型変換はどうしても遅いので出来るだけ避けてください。
小数以下があろうとなかろうと浮動小数点には関係の無いデータの持ち方をしているので変換時間には関係のないことなのです。

難しい話になりますが、浮動小数点の変数上は整数部を持たず小数以下の値しかありません。桁を表すのは指数部が行います。更に2進法だったりすので更にややこしいのです。
「浮動小数点数 - Wikipedia」
http://ja.wikipedia.org/wiki/%E6%B5%AE% ... 9%E6%95%B0
「浮動小数点数」
http://www.jtw.zaq.ne.jp/kayakaya/new/k ... t/fudo.htm
ややこしいので興味があったら読んでみてください。
後、浮動小数点は徐乗算よりも加減算のほうが遅い特徴があり、浮動小数点演算回路次第では加減算の速度低下には気をつける必要があります。PSPの場合は、速度が落ちるのか必ず確認するようにしてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#42

投稿記事 by COFE » 12年前

http://www.geocities.jp/daichi1969/synt ... .html#osc5
こういうページを見つけました
ここに書いてある

コード:

inline int _FLOAT2INT(float f)
{
    int i;
    __asm__ {
        fld     dword ptr [f]
        fistp   dword ptr [i]
    }
    return i;
}
これでfloatを渡すとintになって帰ってくるようなんですが、コレも遅いほうですか?
それ以前に、CPUが違う場合はアセンブリに互換性がなかった気がするのですが、上のコードはPSPで使えますか
あと、出来れば上のアセンブリが何をやっているか教えてもらいたいです

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#43

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:これでfloatを渡すとintになって帰ってくるようなんですが、コレも遅いほうですか?
それ以前に、CPUが違う場合はアセンブリに互換性がなかった気がするのですが、上のコードはPSPで使えますか
あと、出来れば上のアセンブリが何をやっているか教えてもらいたいです
x86系(パソコン)CPUのアセンブラですね。
パソコンでは使えますがCPUが違うPSPでは使えません。PSPのCPUは、MIPS R4000 です。
「R4000 - Wikipedia」
http://ja.wikipedia.org/wiki/R4000
まぁ、気合があったら読んでみてください。英語マニュアルです。
MIPS R4000 Microprocessor User's Manual
http://groups.csail.mit.edu/cag/raw/doc ... ok_Ed2.pdf

一応大雑把に説明しておくと
fld dword ptr [f] 浮動小数点レジスタに浮動小数点値をfからロードします。
fistp dword ptr  浮動小数点レジスタの値をintに変換してiにストアします。
もちろんPSPでは使えませんよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

たかぎ
記事: 328
登録日時: 13年前
住所: 大阪
連絡を取る:

Re: 省メモリと動作速度

#44

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

MIPS R4000の場合、int→floatの変換は、mtc1とcvt.s.wの2命令が必要です。
逆に、float→intの変換は、trunc.w.sとmfc1の2命令です。
各命令はいずれも数サイクルの命令ですが、同じFPUレジスタを使いまわすので連続で使えなかったはずです。
文脈次第では結構遅くなることがあります。
アセンブリ言語でのコーディングは、よほど熟練していないと高速化できませんので、なるべく避けることをお勧めします。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#45

投稿記事 by COFE » 12年前

色々と考えてみたのですが
引数をfloatで渡す→ラジアンを度数法に変換→テーブルの内容を引っ張る→return mysin[kakudo]
これがしたかったらどう考えてもfloat→intの変換がどこかで必要になってくると思うのですが……
どうしましょう?アイディア尽きてきました

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#46

投稿記事 by softya(ソフト屋) » 12年前

COFE さんが書きました:色々と考えてみたのですが
引数をfloatで渡す→ラジアンを度数法に変換→テーブルの内容を引っ張る→return mysin[kakudo]
これがしたかったらどう考えてもfloat→intの変換がどこかで必要になってくると思うのですが……
どうしましょう?アイディア尽きてきました
絶対、度数法と言うよりfloat→int型の変換は配列の添字参照で一度は必要ですよ。
ただ、何度も変換しないように工夫しないといけません。私は一回もするなとは言っていませんので読みなおしてみてください。
そういう意味で、私の提案(Sin関数の引数がラジアン角、Sin関数の内部は度数法に変換して処理)ではダメなのですか?
その理由を教えてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#47

投稿記事 by COFE » 12年前

あ、そうだったんですね
ずっと悩んでました
だったら昨日出したNo40はどうでしょう?
float→intの変換は一回に抑えれてるはずです

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#48

投稿記事 by softya(ソフト屋) » 12年前

NO.40だと暗黙の型変化ののままなのが気になりますが、一応変換は一回だけのようです。
ただ、コンソールでも良いので動作テストプログラムを組んでみてください。色々と問題があります。
DrawPixelぐらいなら古いパソコンでも耐えるのでDXライブラリでも良いです。
見た目にすごく分りやすいのでDXライブラリをお勧めしますが。

[補足]
問題点は、度数法への変換部分と全く別の部分です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#49

投稿記事 by COFE » 12年前

父親のパソコン無理やり奪ってテストプログラム作ってみます

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#50

投稿記事 by softya(ソフト屋) » 12年前

実行できるパソコンが無いのなら
「codepad」
http://codepad.org/
このWEB上でコンソールアプリなら実行できますよ。

こんな感じで使います。
http://codepad.org/VaFH0WIc
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#51

投稿記事 by COFE » 12年前

そのサイト便利ですねー
javascriptとかcgiだけでCコンパイラと同じ挙動示させるなんてすごいですね
とりあえず(父親のパソコンで)作ってみました

コード:

#include <DxLib.h>
#include <math.h>

#define PI 3.1415926f
float mysin[91];
void InitSin(){
	int i;
	for(i=0;i<90;i++){
		mysin[i]=sin(PI/90*i);
	}
}

float Sin(float rad){
	int kakudo;
	kakudo=rad*180/PI;

	if(kakudo<0){
		kakudo=-kakudo;
	}
	if(kakudo>90){
		kakudo=kakudo%90;
	}
	return mysin[kakudo];
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	ChangeWindowMode(TRUE);
	if(DxLib_Init()==-1) return -1;

	InitSin();

	for(int i=0;i<90;i++){
		printfDx("度数法 %d 度 → Sin %f\n",i,Sin(PI/90*i));
	}
	ScreenFlip();
	WaitKey();
	return 0;
}
コンソールで書けよこんなプログラムってツッコミは置いといてください
http://www.game-create.com/archives/261
ここのサイトの表と比べてみたのですが、明らかに違うんですよね……
調べても変なところは無いし(無いはず無いけど)
どこがダメですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#52

投稿記事 by softya(ソフト屋) » 12年前

まぁ、色々と変な所があるから、こうなるわけです。
「C++ code - 47 lines - codepad」
http://codepad.org/eABdWOgy
コンソールでも、これだけ表現力があると言う見本をお見せします。
*マークが普通のサイン波で、oマークがCOFEさんのサイン波です。

まず、初期化が怪しいです。その他マイナス処理とか90度を超えた時とか色々と問題があるんです。
COFE さんが書きました:avascriptとかcgiだけでCコンパイラと同じ挙動示させるなんてすごいですね
実際にはサーバー側でコンパイラが動いています。
なので、cgi自体がコンパイラの働きをしているわけではないですよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#53

投稿記事 by COFE » 12年前

おお、これは美しい
そして私のsin波(笑)
いやはやとんでもないもの作ってたんですね、お恥ずかしい
もうちょっと研究してきます

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#54

投稿記事 by COFE » 12年前

コード:

#include <DxLib.h>
#include <math.h>
#define PI 3.1415926f
float mysin[91];
void InitSin(){
	int i;
	for(i=0;i<90;i++){
		mysin[i]=sin(PI/180*i);
		mysin[i]=mysin[i];
	}
}

float Sin(float rad){
	int kakudo;
	kakudo=rad*(360/(2*PI));

	if(kakudo<0){
		kakudo=kakudo%90;
		kakudo=-kakudo;
	}
	else if(kakudo>90){
		kakudo=kakudo%90;
	}
	return mysin[kakudo];
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	ChangeWindowMode(TRUE);
	if(DxLib_Init()==-1) return -1;

	InitSin();

	for(int i=0;i<90;i++){
		printfDx("%f",mysin[i]);
		if(i%5==0 && i!=0) printfDx("\n");
		DrawCircle(Sin(PI/90*i)*500,5*i,2,GetColor(255,0,0),TRUE);
		DrawCircle(sin(PI/90*i)*500,5*i,2,GetColor(0,0,255),TRUE);
	}
	ScreenFlip();
	WaitKey();
	return 0;
}
mysin配列の内容はちゃんとしたものが入るようになりましたが、なぜか美しいsinカーブを描きません
配列内がちゃんと初期化されているのに失敗するのだからSin関数が怪しいのだろうけど……
日記みたいな書き込みですいません、もうちょっと頑張ってみます

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#55

投稿記事 by softya(ソフト屋) » 12年前

分り易くなるようにグラフ風に変えてみました。
あと同じ大きさだと重なって見えないので赤い円のサイズを3にしてあります。

コード:

#include <DxLib.h>
#include <math.h>
#define PI 3.1415926f
float mysin[91];
void InitSin(){
	int i;
	for(i=0;i<90;i++){
		mysin[i]=sin(PI/180*i);
		mysin[i]=mysin[i];
	}
}

float Sin(float rad){
	int kakudo;
	kakudo=rad*(360/(2*PI));

	if(kakudo<0){
		kakudo=kakudo%90;
		kakudo=-kakudo;
	}
	else if(kakudo>90){
		kakudo=kakudo%90;
	}
	return mysin[kakudo];
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	ChangeWindowMode(TRUE);
	if(DxLib_Init()==-1) return -1;

	InitSin();

	int sx,sy,cb;
	GetScreenState(&sx,&sy,&cb);
	int cy = sy/2;

#define START_KAKUDO (-180)	//(-360)
#define END_KAKUDO (360)	//(720)
	for(int i=START_KAKUDO;i<=END_KAKUDO;i++){
		//     printfDx("%f",mysin[i]);
		//     if(i%5==0 && i!=0) printfDx("\n");
		int px = (i-START_KAKUDO)*sx/(END_KAKUDO-START_KAKUDO);
		DrawCircle(px,Sin(PI/90*i)*(-sy/3)+cy,3,GetColor(255,0,0),TRUE);
		DrawCircle(px,sin(PI/90*i)*(-sy/3)+cy,2,GetColor(0,0,255),TRUE);
	}
	for(int i=START_KAKUDO;i<=END_KAKUDO;i++){
		int px = (i-START_KAKUDO)*sx/(END_KAKUDO-START_KAKUDO);
		if( (abs(i)%45)==0 ) {
			DrawLine(px,0,px,sy,GetColor(255,255,255),TRUE);
			DrawFormatString(px+4,cy-20,GetColor(0,255,255),"%d",i);
		}
	}
	DrawLine(0,cy,sx,cy,GetColor(255,255,255),TRUE);
	ScreenFlip();
	WaitKey();
	return 0;
}
どうですか? 何か法則性のある問題点を感じませんか?
sin.png
sin.png (40 KiB) 閲覧数: 16225 回
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#56

投稿記事 by COFE » 12年前

できました!

コード:

float Sin(float rad){
	int kakudo;
	int minus=0;
	kakudo=rad*(360/(2*PI));
	if(kakudo<0) minus=1;
	kakudo= minus?-kakudo:kakudo;
	if(kakudo % 360 > 180){
		kakudo=kakudo%180;
		return minus ? mysin[kakudo]: -mysin[kakudo];
	}
	else{
		kakudo=kakudo%180;
		return minus ? -mysin[kakudo] : mysin[kakudo];
	}
	return -1;
}
コレでいいですかね?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#57

投稿記事 by softya(ソフト屋) » 12年前

残念ですが、90度から180度を初め何箇所か間違っています。私のプログラムで表示してみてください。
あと、細かい所で問題があるのですがあとで書きます。

[追記]

コード:

float Sin(float rad){
    int kakudo;
    int minus=0;
    kakudo=rad*(360/(2*PI)); 代入時に型が変わっているのでキャストしてくださいね。gccなどコンパイラによっては警告が出来ます。
    if(kakudo<0) minus=1; ここを minus = kakudo<0;とした方が良いです。条件計算式の直接代入です。
    kakudo= minus?-kakudo:kakudo;
    if(kakudo % 360 > 180){ あとの問題はここですね。もっと細かく象限分けをしないとダメですよ。
        kakudo=kakudo%180;
        return minus ? mysin[kakudo]: -mysin[kakudo];
    }
    else{
        kakudo=kakudo%180;
        return minus ? -mysin[kakudo] : mysin[kakudo];
    }
    return -1;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#58

投稿記事 by COFE » 12年前

おはようございます
昨日やったときは青色のカーブとちゃんと重なってくれたのですがやっぱり手直しが必要なんですね

コード:

if(kakudo % 360 > 180){ あとの問題はここですね。もっと細かく象限分けをしないとダメですよ。
ここはなんか難しいですよね、昨日もだいぶ悩んでいたところです、もうちょっと研究してきます

一つ質問なんですが

コード:

if(kakudo<0) minus=1; ここを minus = kakudo<0;とした方が良いです。条件計算式の直接代入です。
↑これもやはりsoftyaさんに教えてもらったヤツのほうが早いのですか?
添付ファイル
無題.png
無題.png (46.8 KiB) 閲覧数: 16199 回

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#59

投稿記事 by softya(ソフト屋) » 12年前

変ですね・・・。
もしかして、テーブルを90度から180度に増やしませんでしたか?
こちらでは90度から180度、270度から360度の表示はおかしくなりましたよ。
テーブルが90度までしか無いのに180度まで参照しているので当たり前なんですが。
ちなみに、速度を最優先にするなら360度を持っていたほうが良いですけどね。

>これもやはりsoftyaさんに教えてもらったヤツのほうが早いのですか?
明確な速度差があるかは実測してみないと分からないですが、minus = kakudo<0;の方がシンプルですし、真偽値を入れるんだと明確にするならC++なら本当は
bool minus = kakudo<0;
と書いてもらうのが一番良いですです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#60

投稿記事 by COFE » 12年前

すいません、コードを全部出します

コード:

#include <DxLib.h>
#include <math.h>
#define PI 3.1415926f
float mysin[181];
void InitSin(){
	int i;
	for(i=0;i<180;i++){
		mysin[i]=sin(PI/180*i);
		mysin[i]=mysin[i];
	}
}

float Sin(float rad){
	int kakudo;
	int minus=0;//後でboolに
	kakudo=rad*(360/(2*PI));
	if(kakudo<0) minus=1; //bool minus = kakudo<0;←コレのほうが早い
	kakudo= minus?-kakudo:kakudo;
	if(kakudo % 360 > 180){
		kakudo=kakudo%180;
		return minus ? mysin[kakudo]: -mysin[kakudo];
	}
	else{
		kakudo=kakudo%180;
		return minus ? -mysin[kakudo] : mysin[kakudo];
	}
	//ここまで
	/*if(kakudo>0){
		if(kakudo % 360 > 180){
			kakudo=kakudo%180;
			return -mysin[kakudo];
		}
		else{
			kakudo=kakudo%180;
			return mysin[kakudo];
		}
	}
	else{
		kakudo=-kakudo;
		if(kakudo % 360 > 180){
			kakudo=kakudo%180;
			return mysin[kakudo];
		}
		else{
			kakudo=kakudo%180;
			return -mysin[kakudo];
		}
	}*/
	return -1;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	ChangeWindowMode(TRUE);
	if(DxLib_Init()==-1) return -1;

	InitSin();

	int sx,sy,cb;
	GetScreenState(&sx,&sy,&cb);
	int cy = sy/2;

#define START_KAKUDO (-180) //(-360)
#define END_KAKUDO (360)    //(720)
	for(int i=START_KAKUDO;i<=END_KAKUDO;i++){
		int px = (i-START_KAKUDO)*sx/(END_KAKUDO-START_KAKUDO);
		DrawCircle(px,Sin(PI/90*i)*(-sy/3)+cy,3,GetColor(255,0,0),TRUE);
		DrawCircle(px,sin(PI/90*i)*(-sy/3)+cy,2,GetColor(0,0,255),TRUE);
	}
	for(int i=START_KAKUDO;i<=END_KAKUDO;i++){
		int px = (i-START_KAKUDO)*sx/(END_KAKUDO-START_KAKUDO);
		if( (abs(i)%45)==0 ) {
			DrawLine(px,0,px,sy,GetColor(255,255,255),TRUE);
			DrawFormatString(px+4,cy-20,GetColor(0,255,255),"%d",i);
		}
	}
	DrawLine(0,cy,sx,cy,GetColor(255,255,255),TRUE);
	ScreenFlip();
	while(ProcessMessage()!=-1){
		WaitKey();
	}
	return 0;
}
とりあえず、コレをお見せしたかっただけです

>360度持っていたほうが……
これは配列の宣言をmysin[361];にして正負の判断をすっ飛ばす処理にするってことですよね
今から360の場合の方も書いてきます

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#61

投稿記事 by softya(ソフト屋) » 12年前

やっぱりテーブルを180度まで拡張してましたね。
最後に見せてもらったのは90度までのテーブル板でしたよ。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#62

投稿記事 by COFE » 12年前

ありがとうございます、ついに360度の方も完成しました

コード:

float Sin(float rad){
	int kakudo = (int)(rad*(360/(2*PI)));
	bool minus = kakudo<0;
	kakudo = (minus ? -kakudo : kakudo) % 360;
	return minus ? -mysin[kakudo] : mysin[kakudo];
}
配列の宣言とInitSinもいじってあります
条件演算子を多用して可読性もなんもないですが一応動きます(笑)
早速PSPの龍神録モドキでこのコード使います
softya(ソフト屋) さんが書きました:やっぱりテーブルを180度まで拡張してましたね。
最後に見せてもらったのは90度までのテーブル板でしたよ。
本当に申し訳ありません、見落としていました
ただ、softyaさんって本当にすごいですね、コードも見ずにどのへんが変えられたか瞬時に判断できるなんて

ちょっと前のところで、私に1から考えて作って欲しいと言われましたよね
私が最初質問してテーブル化を教えてもらったときには、同時にテーブル化のコードも教えてもらえるんじゃないかと甘いこと考えてました
しかし、1から自分で作ってみることによって kakudo = 0<kakudo; ←こういう入門書にちょこっと載っていたけどすっかり忘れていた書き方も分かりましたし、正直ちゃんと習ったわけではないので詳しくなかった三角関数もかなり理解を深めることが出来ました
さっき1から考えたとかいいましたが、このSin関数はsoftyaさんの教えがなければ絶対に完成しなかったものだと思います

途中で逆切れしたりしていろいろご迷惑をおかけしました
Sinテーブルが完成したのはsoftyaさんのお陰です
本当にありがとうございました
最後に編集したユーザー COFE on 2011年8月09日(火) 12:13 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#63

投稿記事 by softya(ソフト屋) » 12年前

おめでとうございます。
ただ、cosと0.1版が完成していないですが良いんでしょうか?

それと実際のアセンブラコードを見てみないと分かりませんが、分岐が多いかも知れません=遅い。
MIPS R4000などのCPUでは極力分岐を減らすことが高速化に繋がりますので、工夫したほうが良いかも知れません。

コード:

float Sin(float rad){
    int kakudo = (int)(rad*(360/(2*PI)));
    bool minus = kakudo<0; ← たぶんアセンブラレベルでは分岐。
    kakudo = (minus ? -kakudo : kakudo) % 360; ← これも分岐。
    return minus ? -mysin[kakudo] : mysin[kakudo]; ← これも分岐。
}
なので、最初に一回だけif文で分岐するだけの方が高速かも。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#64

投稿記事 by COFE » 12年前

cosのことすっかり忘れてました
前にcosについてもちょっと言われた気がするのでまた過去ログ漁ってきます
cos出来るまで解決タグまた外しますね

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#65

投稿記事 by COFE » 12年前

できました(多分……)

コード:

float mysin[3601];
void InitSin(){
	int i;
	for(i=0;i<3600;i++){
		mysin[i]=sin((PI/(1800))*i);
		mysin[i]=mysin[i];
	}
}

float Sin(float rad){
	int kakudo = (int)(rad*(1800/PI));
	bool minus = kakudo<0;
	kakudo = (minus ? -kakudo : kakudo) % 3600;
	return minus ? -mysin[kakudo] : mysin[kakudo];
}

float Cos( float rad ) {
	return Sin( rad+PI/2 );
}
0.5*(PI/180)を渡したところ0.008727が帰ってきましたのでたぶん大丈夫です
Cosは前にsoftyaさんに教えてもらったののそのままパクりですw

コード:

kakudo = (minus ? -kakudo : kakudo) % 3600;
return minus ? -mysin[kakudo] : mysin[kakudo];
この部分は「やっヴぇwww俺かっこいいwww」って感じでお気に入りの箇所だったんですが、実行速度には変えられないので元に戻します

これでsinテーブル(度数法で小数第一位まで)+cos完成と考えていいですか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#66

投稿記事 by softya(ソフト屋) » 12年前

おつかれ様でした。
気にる所を一箇所だけ。バグではないですが。

コード:

float mysin[3601];
void InitSin(){
    int i;
    for(i=0;i<3600;i++){
        mysin[i]=sin((PI/(1800))*i); ← 明示キャストを希望。速度には関係ないですが。
        mysin[i]=mysin[i]; ← ここいらないのでは?
    }
}
 
float Sin(float rad){
    int kakudo = (int)(rad*(1800/PI));
    bool minus = kakudo<0;
    kakudo = (minus ? -kakudo : kakudo) % 3600;
    return minus ? -mysin[kakudo] : mysin[kakudo];
}
 
float Cos( float rad ) {
    return Sin( rad+PI/2 );
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

COFE
記事: 97
登録日時: 13年前

Re: 省メモリと動作速度

#67

投稿記事 by COFE » 12年前

ありがとうございます
該当箇所は書き直しておきました

しかし3日もかかりましたね
正直こんなにかかるとは思いませんでした
(私一人の力でやってませんが)ここまでsinテーブル書いてきていろいろ知れていい経験になったと思います

またなにかあったら質問させて頂きます

最後になりますが本当にありがとうございます

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 省メモリと動作速度

#68

投稿記事 by softya(ソフト屋) » 12年前

PSPで高速化と言うのは、こういう事の積み重ねかと思います。
つまり、知識や手間が必要という事ですね。

究極の最適化は、
・実時間の実測 → ネックとなるポイントの洗い出し
・無駄がないかアセンブラレベルのコードの確認。
・vfpuなどの活用。
・アルゴリズムのレベルからループ回数の節約方法を検討。
などなどを繰り返すことです。
がんばってください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 省メモリと動作速度

#69

投稿記事 by ISLe » 12年前

コード:

float Sin(float rad){
    int kakudo = (int)(rad*(1800/PI));
    if (kakudo < 0) {
        kakudo = -(kakudo + 1);
        kakudo %= 3600;
        kakudo = 3600 - 1 - kakudo;
    } else {
        kakudo %= 3600;
    }
    return mysin[kakudo];
}
こっちのほうが速いかもしれません。

閉鎖

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