忍者ブログ
Profile
HN:gp-hss

職業:高校生

趣味:3DCG

言語:C全般

環境:VC++ 2008 EE

3DCG:Softimage Mod Tool

自己紹介:
ゲームプログラマー目指して勉強している者です。
現在 C++ 修得にむけて頑張っています。

Began study since 2009/8/21

Latest CM
[06/28 soulmorning]
Latest TB
2  3  4  5  6  7  8  9  10 
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

author : gp-hss ×

ふぅ~む。
だめだなこりゃ。
そもそも無理があったんだ。
浮動小数点数の精度で表すことのできる桁を超えちゃってるから・・・・。





どうもです。
どうやらこのシリーズも Part.4 に行く前に終わっちゃいそうです。
当然のことながら時間というものは小さければ小さいほど動きが激しいですよね。
つまりは、小数点以下が低ければ低いほど数値の動きが激しいということです。
しかも、何度か計測時間を比較したところどれもナノ秒以上の桁はちゃんとあります。
しかし最後の桁がほとんど 8, 6, 4, 0 のどれかで値をとっているのです。
そこで思いました(遅すぎですが)。
こりゃ~浮動小数点数の精度を超えちゃってるなと。
 double型 で保障されている精度は 6桁 までです。
ですので余裕で超えちゃっているわけです。
だから少数点以下が低ければ低いほど精度が低いのか・・・。
ちなみに long double の型の変数に格納してもさして変化はありません。
(精度は処理系依存だと思うので、あなたのパソコンでは違うかもしれません。)
だから、たぶん小数点以下中ごろから数値が狂ってきていると思われます。
たぶん数値が丸められているのかな?
ゆえに、各桁の数値がかぶってきてしまうのです。
でも、一応これに対処するためプログラム中ではどの桁から数値をとってくるか変えています。
それでもあまり変化はありません。
これが第一の問題です。

第二の問題には、いくら処理時間が違うとはいえ小数点以下上位の数値は同じようなものになってしまいます。
だからこそ、小数点以下下位の方から数値を取ってきたいのに浮動小数点数の精度を超えてしまっているせいで値が丸められます。
ゆえに、同じような数値ばかりが返ってきてしまうのです。
よって生成される乱数も同じような数値ばかりになってしまいます。
例えば、乱数を生成する範囲を 0 ~ 100 までとした場合、1桁の乱数は 1 ばかりが頻出します。
2桁の乱数も同じような数値ばかりが頻出します。
よって、ものすごく精度の悪いものになってしますのです。

これらの問題から無理があるなと感じました。
少なくとも今の僕の実力では解決することは難しいです。
しかし!
今回のプログラミングは大変勉強になりました。
いろいろな知識が得られたと思います。
これからはたぶんゲームを作っていきますのでどうぞお見届けください。


(てぇ~ことは結局のところ Part.4 はお目にかかんないの?・・・・・・・・・。)

拍手[0回]

PR
author : gp-hss ×

test_create_rand_val(.c)

test_create_rand_val(.exe)

Part.2 のプログラムをさらに改良しています。
論理上不要な部分を無くし、さらに乱数を求める処理を 100 分の 1 にまでスピードアップさせました。
精度は 9 割維持しています。
ですが、指定した乱数を生成する範囲が狭すぎると一定の間隔で同じ数値の乱数が生成されてしまいますし、逆に範囲が広いと同じような数値の乱数ばかりが生成されてしまいますし、
外部ファイルを使わなくても済むようにしたので、一番最初に返される乱数の値がかぶってしまう確立が高くなってしまっています。
まぁこれらの問題はものすごくがんばれば解決できると思うので Part.4 では完成形を披露できたらなと思っています。

このソースの解説を簡単にしておきましょう。
といってもまぁ解説するところなんてほとんどありませんよね・・・。

まずは、自作の乱数を求める関数を header にしたものをインクルードしています。
そして、僕のつくった乱数を生成する関数は、まず最初に必ず乱数をどの範囲から生成するか指定しなければいけません。
それが、

    crv_scope()

です。
第一引数に範囲の始めの値、第二引数に範囲の終わりの値を渡します。
ちなみに、範囲は 0 ~ 1000000 までです。
負の乱数にしたければあとで符号変換してやればいいだけです。
範囲はプログラム中どこででも変えることができます。

次に、その範囲内で乱数を生成する関数である

    CRV()

ですが、こいつは呼び出すごとに指定した範囲内において乱数を返します。
また、範囲を指定する関数である crv_scope() を先に呼び出していない場合は -1 を返します。
あとは、もう一度乱数を生成するかどうかを聞いて、もう一度する場合は do文 によって同じ処理をさせています。

どうでしたか?
乱数を作り出すプログラムはいろいろな作り方があるのでしょうが、簡単な理屈でもいいので自分で作ってみるというのが重要ですよね。

ではまた今度。

拍手[0回]

author : gp-hss ×

rand_val_info(.txt)
rand_test(.exe)
rand_val(.zip)
.txt ファイルを .exe ファイルと同じディレクトリ内に置いてください。
zip はそれらをまとめたものです。
または、 txt ファイルへのリンクをクリックしたあと、実行ファイルを実行してください。


今回は Part.1 でつくったプログラムに加工を加えて、精度を高くしたり範囲を指定できるようにしています。
たとえば、Part.1 の test.exe では小数点第2位から2桁だけ数値を取っていましたが、今回のプログラムではあるアルゴリズムに沿って、ある位から少なくとも6桁以上の数値を取ってきています。
ある位とは、少なくとも小数点第2位以下です。
あとは、取ってきた数値を指定どおりに成形していきます。

まぁこの成形処理はものすごく簡単です。
範囲の終わり値に + 1 したものと取ってきた数値とを割った余りを求めるだけです。
ただし、これは範囲の始め値が 0 の場合のみのことですね。
そこで、まず始め値が 0 でない場合はその始め値で終わり値を引きます。
あとは始め値分引かれた終わり値 + 1 で割った余りを求め、最後に始め値の値を足します。

ただし、ここに関わってくるのが強化した精度の制約です。
この精度の制約をクリアしないと求めた値は乱数として認められず、もう一度乱数を作らせます。
実は精度を高くするために txt ファイルがいるのです。
まぁ無くてもそこまでかわらないのですが、ないよりあったほうがマシなのです。

ちなみにこのプログラムに似たようなものは Part.1 の内容と自分で調べてみる探究心があればつくれるはずです。
ぜひがんばってつくってみてください。

拍手[0回]

author : gp-hss ×


test(.exe)

どうもです。
今回はコンピュータの処理時間を取得してそれを乱数にしてしまおうという目論見のもとプログラミングしていきました。
全く同じ処理でも絶対に同じ処理時間ではないだろうと思っていたのでやってみようということになったのですが、この場合取得できる時間が秒単位では精度が悪すぎます。
ですので、まず高い精度で時間を取得できる関数を探しました。
検索したところいろいろあったのですが、少なくともマイクロ秒(100万分の1秒だったと思う)ぐらいはほしいので、 gettimeofday などの関数を使おうかと思ったのですが、

    'sys/time.h':No such file or directory

つまり、インクルードしなければいけない sys/time.h が存在しないのです。
一応自分でも sys フォルダ内を見てみたが、似たようなのはあるのだが確かに time.h はなかった。
別の方法を探すことにしましょう。

そこで見つけたのがパフォーマンスカウンタの現在値を調べるものでした。

「パフォーマンスカウンタとはなんだ!?」
CPUの内部に搭載されている、CPUクロックを元にカウントしているカウンタのことである。
こいつはパソコンに電源が入ると同時にカウントを始める。

よって、「計測したい処理を開始する前のカウンタの現在値」※1と、「処理が終わった後のカウンタの現在値」※2を取得することで処理中にどれだけカウントしたかが分かる。
求め方は ※2 から ※1 を引くだけでよいのです。
あとはその差分をカウンタの1秒あたりの周波数(クロック周波数)で割ることで秒単位の時間が得られるわけです。
では、それぞれを値を得る関数を紹介します。

QueryPerformanceCounter()
QueryPerformanceFrequency()

それぞれカウンタの現在値と周波数を得る関数です。
それぞれの関数には数値を格納するための変数のアドレスを渡します。
その変数の型は LARGE_INTEGER 型となります。
ちなみに LARGE_INTEGER は大きな整数を扱う型(ていうか共用体です)なのですが、大きすぎて LowPart , QuadPart などという風に分けられていていろいろ面倒なので、今回は __int64型 を使います。
(この型についての詳細は自分で調べてみてください。)
よって、


__int64 start, end, freq;

QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
QueryPerformanceCounter((LARGE_INTEGER *)&start);

//計測したい処理

QueryPerformanceCounter((LARGE_INTEGER *)&end);


という風な感じになります。
あとは、カウンタ値の差分をクロック周波数で割ります。
その値を格納する変数を pastmsec とします。
さらにそれに 1000 をかけたものを rand_val としたのが、上記の test.exe です。
(試験ファイルですので 30 回出力させています。)
しかし、このままでは乱数としては精度が悪すぎるのです(同じ数や似たような数値ばかりがでてしまう)。
そこでとりあえず、出力する数値が直前に出力した数値と同じ場合は出力しないようにしています。
ですので1桁の数字がないところがところどころあるかもしれませんが、こういうことなので気にしないでください。
ちなみに計測している処理は、 1千万回の空文 です。
 

拍手[1回]

author : gp-hss ×
ball_yoke(.exe)
ball_yoke(.c)

ちょっとプレイヤーの球が意図した動作にはならないのですが、上出来です。
あとはこれを一つ一つのボールが降ってくるのではなく、複数のボールが降ってくるようにできればOKなんですが、それはまた改めて。

ではまた今度。
(あっ・・・・説明変えるの忘れてた・・・。)

拍手[0回]

author : gp-hss ×
忍者ブログ | [PR]
 | PAGE TOP
write | reply | admin