2010年8月21日
#
右辺値参照を調べてわかった事。
右辺値参照はオブジェクトのコピーをするときに
条件さえ整えば高速におこなう事を目的に作られた構文です。
右辺値参照が役に立つのは、関数内でポインタの形で情報を持っているものに限られます。
ですから、直接値を持つ形になっているクラスには何の貢献もしません。
具体的には、以下のような例です。
/* 役に立つ例 */
class MyString{
char *string;
}
/* 役に立たない例 */
class Matrix44{
float m[4][4];
}
下の例の行列なんかは演算子オーバーロードで書ければすっきりするのですが、
実際にはそういうわけにはいきません。
/* こんな関数は速くならない */
Matrix44 operator +(const Matrix44 &in1, const Matrix44 &in2);
/* 現実的な解 */
void Add(Matrix &out, const Matrix44 &in1, const Matrix44 &in2);
右辺値参照を最初に聞いた時、こんな事ができる!と期待してました。
/* 私がやりたかった事 */
auto operator +(const Matrix44 &in1, const Matrix44 &in2) -> Matrix44 &out{
for(int x = 0; x < 4; x++){
for(int y = 0; y < 4; y++){
out[x][y] = in1[x][y] + in2[x][y];
}
}
}
返り値を受け取る変数って、関数を呼び出した時点で
破壊されているものとみなしてもいいと思うんですよ。(例外やlongjmpは無視)
そして、その返り値を受け取る変数の参照が欲しい!!
ということで名前付き返り値なんてものがあってもいいんじゃないかな~。
VBなんかが返り値は関数名と同名の変数に入れるタイプですね。
と思ってたら、どうやらReleaseモードでの最適化で似たような事をしてくれるらしいです。
(以下の記事のコメント欄参照)
http://blogs.wankuma.com/episteme/archive/2010/08/06/192085.aspx
…最適化してくれるのなら右辺値参照はいらない子なんじゃと思う今日この頃です。
コピー以外に使い道はあるんでしょうかね?
2010年7月27日
#
今回の夏コミもサークルを出します。
「8/14(土) 2日目 東-ア46a にじけん」になります。
となりが日本国際事務機器さんですよ!
ここの漫画は面白いですよ! 駄目な現場にいる人ほどオススメ。
でもって、出展物の紹介です。
・ゲーム制作現場の合同誌 ゲームの修羅場2 B5 40p 300円
今回も発行できました、もろもろの合同誌です。
表紙はわらしなママ(小松菜屋)さんです。
内容は以下の通り、今回も濃い目で面白い内容です。
[Interview]
自転車創業 かざみみかぜ。
[Topics]
シューティングゲーム・リズム指向の敵配置 サク(ASTRO PORT)
ハジメテの同人ノベルゲーム製作 柚坂みる(Blank Script)
時代遅れの自前bit単位αブレンド にけ(はづき倶楽部)
Refactor! for C++によるリファクタリング 出水 洸太郎(にじけん)
・Lua開発読本 Second Edition B5 48p 300円
前回発行していたLuaの本をちょっと加筆&修正しました。
まぁ、確か20冊か30冊ぐらいしかなかったはずなので手に取っている人は少ないですね。
相変わらず文字ばっかりで黒いです。
あと、コミケのカットに書いた「ソートの本」ですが…正直進んでません。
WordからInDesignに乗り替えたら、どう使っていいのかわからなくててんてこ舞いです。
今回は図が多いのでその作成に手間がかかっているのもあったりして…。
とりあえず、書けるところまで書いたバージョンを電子書籍(つーか、ただのpdf)で
本を買った人におまけでつけようかな、と考えています。
ということで、今回もよろしくお願いします。
2010年5月2日
#
今、ブロックしないファイル読み込みをやっています。
普通にファイル読み込みを書いた場合、データを読み込む間はプログラムが止まります。
そこを止まらないように作りたいわけです。
まず、Request関数でファイルの読み込み要求を投げます。
あとは、Loading関数がtrueになるまで待機し、trueになったらGetBuffer関数でデータを得ます。
で、出来たのがこんな関数。
このUpdage関数は毎フレーム呼ばれることを想定して作成しています。
void Update(){
switch(state){
case 0:
file.Request("data.dat");
state++;
break;
case 1:
if (file.Loading() == false) state++;
break;
case 2:
config.LoadFromMemory(file.GetBuffer());
state++;
case 3:
file2.Request(config.StageName(stage));
state+;
case 4:
if (file2.Loading() == false) state++;
break;
case 5:
stage.LoadFromFile(file2.GetBuffer());
stageReady = true;
state++;
break;
default:
break;
}
}
しかし、この関数、非常に書いてて苦痛です。
上のソースにはこんな問題点があります。
・コードの追加や削除が面倒
・無駄に1フレーム待つ場所がある
コードに追加や削除をする度に全体のcaseの数値を書き換えなければなりません。
それに、ひょんなことからstate++ を2回書いてしまうというバグの混入が考えられます。
また、上記のプログラム、case 2,3,4まではわざわざbreakする必要がありません。
もっといえば、ファイル読み込みの部分にキャッシュが搭載されていて、
Requestを投げたらすぐにLoading関数がtrueを返す設計の場合、無駄に待っていることになります。
この辺を少し改善したソースがこの通り
void Update(){
switch(state){
case 0:
file.Request("data.dat");
case 1: state = 1;
if (file.Loading() == false) break;
case 2: state = 2;
config.LoadFromMemory(file.GetBuffer());
case 3: state = 3;
file2.Request(config.StageName(stage));
case 4: state = 4;
if (file2.Loading() == false) break;
case 5: state = 5:
stage.LoadFromFile(file2.GetBuffer());
stageReady = true;
default:state = 999;
break;
}
}
少し野暮ったいプログラムになりましたが、前のプログラムに会った
「無駄に待つ」、「state++を2回書いてしまう」という問題点は解決されました。
追加は相変わらず面倒ですが、stateが連番でなくても良いため削除は簡単になっています。
追加を楽にするために、1,2,3ではなく、10,20,30と番号をふったら良いかもしれません。
っていつのBASICや! RENUMよこせ、RENUM!!!
ということで、もっとスッキリ爽快なソースを紹介。
bool Update(){
CoroutineBegin();
file.Request("data.dat");
while(file.Loading()) yield;
config.LoadFromMemory(file.GetBuffer());
file2.Request(config.StageName(stage));
while (file2.Loading()) yield;
stage.LoadFromFile(file2.GetBuffer());
stageReady = true;
state = -1;
CoroutineEnd();
return true;
}
前回のコルーチンの登場です。
どうですか、このスッキリ具合。
ソースは短くなったし、追加、削除での番号振り直しもありません。
コルーチンの内部では暗黒儀式を行っているような気がしますが、
ほら、boostの内部でも暗黒儀式多いですしおすし。
私、脱いだらすごいんです、ということでひとつなんとか。
2010年4月28日
#
C++でコルーチンを作ってみるテストです。
さて、下のソースを見てください。
このFooという関数はまさにコルーチンです。
#include "coroutine.h"
class Test:public Coroutine{
int i;
public:
bool Foo(){
CoroutineBegin();
for (i = 1; i <= 20; i++){
printf("%d ", i);
yield;
if ((i % 3) == 0){
printf("fizz ");
yield;
}
if ((i % 5) == 0){
printf("buzz ");
yield;
}
}
CoroutineEnd();
return true;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Test test;
for (;;){
bool finish = test.Foo();
if (finish) break;
printf("---\n");
}
return 0;
}
実行結果はこんな感じになります。
1 ---
2 ---
3 ---
fizz ---
4 ---
5 ---
buzz ---
6 ---
fizz ---
7 ---
8 ---
9 ---
(以下省略)
コルーチンのyieldが呼ばれる度にメインルーチンに戻ってハイフンと改行が出力されています。
いいですね、コルーチン!
こんな素敵なコルーチンが使えるヘッダファイルが今ならもう一個ついて1980円!
じゃなくて、こちらからダウンロードできます。
#あくまで使用は自己責任で
2010年4月1日
#
テレビCMでおなじみですが、2011年7月でアナログ接続サービスは終了します。
モニタをRGB15ピンでつないでいる人は、2011年7月以降映らなくなるので、
DVI端子の付いたモニタとビデオカードに買い換える必要があります。
また、3色のケーブルでおなじみのRCA端子やS端子を使っている人も買い換えましょう。
D端子は名前からデジタルっぽいですが、これもアナログなので注意してくださいね。
今の機器が使えなくなるのは悲しいですが、デジタルにするといいこともあります。
なんといっても高解像度です
高解像度ならいつものゲームがこんなにも楽しい!
下のスクリーンショットのように、フルHDならではのゲームが楽しめます。
ということでデジタルに移行しましょう!
2010年2月26日
#
たまに良くある計算で、1=2を証明する、と言うものがあります。
こういう式の考え方からいきましょうか。
1と2が等しいわけがないのです。
つまりどこかに計算式におかしい部分があります。
もし計算式にどこもおかしいところがなかったらどうでしょう。
なら、前提が間違っています。
これを「背理法」って言います。
と言うことで、前回の計算を厳密にやっていきましょう。
ここまでは問題がありません。
前回、ここから先に0×0を計算したところから何かがおかしくなってます。
ここで、計算順序に関する2つの法則を見ていきましょう。
交換法則と結合法則です。
前後を入れ替えても特に問題はありません。
交換法則は成り立つようです。
次は結合法則。
前回のおかしい点はここですね。
このhという数を導入すると結合法則が使えない、つまり計算の順序を入れ替えることができません。
結合法則が成り立たないと、交換法則が成り立っても何の意味もありません。
この結合法則が使えないとどうなるか…。
良く見る方程式を見てみましょう。
これは良くやる計算ですが、これはさりげなく結合法則を使って計算順序を変えています。
0除算を範疇に含めて結合法則を捨てると、一気に世界が狭くなってしまいます。
結局、面白い法則も見つかりそうにないし、0除算の世界まで拡張しない方が良さそうです。
ということで、数を数えるところから始まり、ここまで拡張されていきました、と言う話でした。
2010年2月25日
#
複素数でどんな結果も表せるようになった、と以前書きましたが、
実は表せない数だってあります。
それが、0除算と0の0乗です。
では、0除算の中でも0÷0と、0の0乗を見てみましょう。
これらは2つの法則が真っ向から対立しています。
どちらも言っていることは正しいだけに、どちらを採用するかも困ります。
と言うことで、どういう道を選んだか。
「時と場合による」
0÷0と、0の0乗というのは、いきなり出てきたりしません。
その計算が出てくる背景を考え、そこで適切な答えを出そう、って事です。
例えば、a÷aという式がもともとあり、そこにa=0を入れてしまったのなら、
その時に出てきた0÷0は1じゃね?というわけです。
逆に言えば、その計算の背景がわからないのなら、答えは出せません。
さて、1÷0はどうでしょう?
無限大、と答えたくなるこの計算結果、とりあえずhと置いてみましょう。
すると、こんな式ができます。

0には何をかけても0、という法則を打ち破る数字が出てきました。
今までなかった新しい数字のようです。
これを使って、ちょっと計算してみましょう。
1=hです。いきなりhの正体がわかりました!
…そんなわけありませんね。
次回で最終回、この謎に挑みましょう。
2010年2月23日
#
虚数は一つなのか…。
そもそも、虚数というのは目で見えない数です。
同じ数を2回掛けたら-1になる数が、今使われているi の他にあるんじゃないか?
とりあえず、それをj とします。
そして、i とj を掛けたときを計算します。
途中ぶっ飛ばしてますが、i とj を掛けた結果も-1という事がわかります。
これでは、i とj を2つ作って分けた意味がないですね。
ところが、もうひとつ、k という新しい虚数を加え、虚数は3つあった!という事にするとうまくいきます。
これを1つの実数と3つの虚数、全部で4つあることから四元数(クォータニオン)といいます。
先ほどの問題、i とj を掛けるともうひとつの文字、k になる、という風に法則を作ります。
しかし、これにはからくりがあって、こんな式も存在します。
そう、計算式の前後を入れ替えると結果が変わります。
四元数は交換法則が成り立たないという条件でようやく成立する世界で、
もし、交換法則を成り立つように作ると虚数が1つしか存在できません。
四元数のさらに上には八元数、十六元数というものがありますが、
そのたびに今まで使えていた法則が使えなくなってきます。
例えば、八元数は結合法則が成り立ちません。
結合法則が成り立たない、と言うことは計算の順序をかえてはいけない、と言うことです。
四元数は3D空間における回転、姿勢制御などに使われているのですが、
八元数以上となると理論はあるものの、使い道がないそうです。
次回は、複素数でも埋められなかった穴の話です。
2010年2月22日
#
前回出てきた「i 」こと虚数を基本から考えます。
そもそも、虚数とは普通の数ではありません。
例えば、「リンゴがi 個」といわれても、「あいこ??」となり意味がわかりません。
「i を2回足す」なら分かりますが、「2をi 回足す」は意味がわかりません。
幸い、「i を2回足す」と「2をi 回足す」は結果が同じと言うことがわかっているので、
意味が多少わかる「i を2回足す」と同じ結果にする、という法則ができました。
なら、入れ替えられない「i をi 回足す」というのはどうでしょう。
しかし、こちらに関してはあっさり解決しました。
そもそもの、i の定義です。
そう、「i をi 回足す」は「-1」とすると決めていたので、これについては答えが決まりました。
しかし、「2をi 回掛ける」には対向できません。
「i を2回掛ける」なら意味がわかりますが、累乗は掛け算とは違い交換できません。
ということで、偉い数学者が計算した結果がこれ。

eってのは大体2.7ぐらいの値で、要は「約2.7をi 回かけたときなら、計算出来たよ!」って事です。
ここで注目するのはsinとcosです。
これは「角度から距離を求めるときに使うもの」です。
幾何学、つまり図形を使ってあれこれ考える所から生まれたのがsinとcosです。
三角形の角度から辺の長さを求めようとしていたときにできました。
リンゴが3個、というところからスタートして、式だけをずっと追い求めていたら、
いつの間にか三角形の角度がどうのこうのという世界に舞い込んでしまっていた…。
前回の式をもう一度見てみましょう。
「i をi 回掛けた値」には円周率のπが使われています。
この円周率という値も図形の世界の数です。
リンゴが3個、という世界では、円周率は違う世界の話でした。
リンゴが3個の世界は、図形の世界と繋がっていた、
もう少し言うと、図形を使えば複素数の世界が目で見て図形で理解できる。
そして、図形の世界で発見された知識が、リンゴが3個の世界に応用出来る。
次回は、虚数は一つなのか、という話です。
2010年2月21日
#
自然数と足し算だけの世界から、こんな計算を行う必要がありました。
□+3=5 □に入る数はなに?
ここで、足し算の逆をする計算が出てきます。
引き算ですね。
「繰り返す」の次は「逆を行う」という方法で計算方法が増えていきます。
足し算からは引き算、掛け算からは割り算、累乗(ダガー表記)からは根です。
最後の根は平方根、立方根という名前の方が有名でしょう。
しかし、自然数しかない世界から新しい数を作らなければならなくなります。
たとえば、引き算ができたことで、「3-5」の結果はどうなるのかわからなくなりました。
ここで、マイナスの数という物導入し、「3-5」には-2を割り当てることにしました。
「足し算の逆を作ったら、負の数という新しい数が出来た」
これは、掛け算の逆にも言えます。
5÷2は2.5、または
です。
これは整数の範疇にない数であり、またもや新しい数ができる、という訳です。
最後は累乗、ここでは二乗すると2になるという無理数や、
二乗すると-1になる虚数が登場しました。
虚数とそれまで発見された数(実数)をあわせて複素数と言うのですが、
複素数は数の拡張を終わらせてしまいました。
終わらせた、というのはこれ以上数を拡張する必要がなくなった、という意味です。
例えば…「二乗すると虚数になる数」や「虚数の虚数乗」という
一見そんなのあるの?と思ってしまう数ですら複素数の範疇で計算できてしまうわけです。
式で表すとこんな感じです。
なぜこんな値になるのか、ってのは教科書数冊分になるので飛ばします。
ただし、「複素数さえあればこれ以上数の拡張をしなくて済む事になった」ってことです。
逆に、「これ以上数を増やさずに済んだ」事と、
先程上げたような不思議な式ですら計算出来た、と言うことが虚数を受け入れられた理由の一つです。
次回は、もう一つの複素数のお話。
今回ついてこれなかった人も原点から別の角度で解説します。