今から海外。何も準備してないがいいのか。 _
いや、今から準備するか…あと一時間しか無いが…。 _
メール見れないので連絡する場合はテレパスなどをご利用ください。 _
そろそろ真面目になんとかしたほうが。 _
帰ってきた。(のは昨日) _
_ floatの加算とintのインクリメントを同時に計算する
int ix,iy; float fx, fy; while ( ... ) { ix ++; iy ++; fx += dx; fy += dy; }
こんな感じのコードがあったとする。 _
今のCPUは大体 int もしくは float ならば4並列で計算する演算器が付いてるので、この演算を一回でやりたいとする。が、intとfloatを混在させるのはできない。が、0〜8388607(=(1<<23)-1)の範囲でインクリメントするだけならなんとかなる、という話。 _
#include <stdio.h> float tof(int x) { float *p = (float*)&x; return *p; } int toi(float x) { int *p = (int*)&x; return *p; } int main() { int i; float sum = 2.0f-(1.0f/(1<<23)); // 0x3fffffff float i1 = -(1.0f/(1<<23)); for (i=0; i<((1<<23)-1); i++) { sum += i1; } printf("%d %d\n", (1<<23)-1, toi(sum)^(0x3fffffff)); return 0; }
こんなコードを考える。2.0f-(1.0f/(1<<23)) = 0x3fffffff。で、これに、-(1.0f/(1<<23))を足してやると、整数のデクリメントになる。 _
そんで、最後に指数部のマスク、仮数部の反転を行えば、色々あって、floatの加算で整数のインクリメントをしたことにできる。指数部は3f800000固定なので、3f800000 | 0x007fffffとのxorを取ればこの指数部マスクと仮数部反転が同時にできる。 _
これを使って、最初のコードは、 _
#include <xmmintrin.h> #include <stdio.h> float tof(int x) { float *p = (float*)&x; return *p; } int toi(float x) { int *p = (int*)&x; return *p; } int func( int n, float x, float y, float dx, float dy ) { float f = 2.0f-(1.0f/(1<<23)); float i1 = -(1.0f/(1<<23)); int i; float result[4]; int mask[4] = {0,0,0x3fffffff,0x3fffffff}; __m128 vsum = _mm_setr_ps(x,y,f,f); __m128 vinc = _mm_setr_ps(dx,dy,i1,i1); __m128 vmask = _mm_load_ps((float*)mask); _mm_store_ps(result,vsum); for (i=0; i<n; i++) { vsum = _mm_add_ps(vsum,vinc); } vsum = _mm_xor_ps(vsum, vmask); _mm_store_ps(result,vsum); printf("%f %f %d %d\n", result[0], result[1], toi(result[2]), toi(result[3])); } int main() { func( 30, 0.5, 1.0, 0.5, 1.0 ); }
こんな感じに書ける。と思ったら最適化したらブッ壊れてた。 _
union fi{ int i; float f; }; float tof(int x) { union fi fi; fi.i = x; return fi.f; } int toi(float x) { union fi fi; fi.f = x; return fi.i; }
こうか… _
んーなんかオンボートのEtherが変だな…リンクしないてなんだ…壊れてんか… _
あれ?繋がった。謎げ。 _
_ 出向
ん。すごい環境だな。 _
何がすごいかというとUnreal Tournament 3の試合をやるという風習があるとかいうような。 _
あと隣の人がずっとWikipedia見てた。 _
installkernelするときにカーネルのバージョンがわからない。menu.lstを書くときにカーネルのバージョンがわからない。 _
man testするとbashのマニュアルが出てきてむずい…と思ったら今の環境そんなことなかった _
zshの履歴保存の仕方がわからなくていつも悩む。HISTFILE,HISTSIZE,SAVEHISTだYO! _
あとほげほげ。 _
最近アセンブリ言語が一番美しいと感じるようになってるな。 _
書いてるプログラムがほとんど最内ループとかばっかりなのでGUIプログラミングとかできる気がしない。 _
hoge _
生きてるます。 _
_ C言語による最新アルゴリズム辞典(AA)
logとかってどうやって書くんじゃい、って感じになったので、買って5年目にして(かどうかは忘れたけど)ようやく役に立つ日が来たようだな。 _
別に書くわけではないんだけど。例えば、精度はいらないから速度が欲しい、NaNの事は考えなくていい、値の範囲がわかってる、等の条件がある場合に、中身がわかってないと工夫できないよなー、と今日必要になったので今まさに本棚から引っ張り出してきた。(そしてまだ何も勉強していない) _
あと、例えば、二回atanfを呼ぶとして、xが同じでyだけが違うときは最適化できるか否か、とか、そういう系。 _
そして、なんでatan2はyとxが逆なんだろうな…(あんまり関係無い) _
math.hの関数実装一覧を眺めたいときは、glibcのソースかなー。 _
あと、Bulletに含まれてるsimdmathとかが良い。X86の実装が無いけど… _
_ 最近なんか今の仕事無くなった時の将来がやたら不安だな
最内ループしか書いてないからな… _
面接官(以下、麺)「前職では何をされてましたか?」 w(以下、w)「ループをアンロールしてました」 麺「ループをアンロール?それはどのような作業でしょうか?」 w「for (i=0; i<N; i++) となっているのを for (i=0; i<N; i+=4) と書きかえて、中身を4回コピペする仕事です」 麺「…それだけですか…?」 w「それで満足いかなかったらfor (i=0; i<N; i+=8)と書きかえて、ループ本体を8個にします」 麺「…それで…」 w「それで満足いかなかったらfor (i=0; i<N; i+=16)と書きかえて、ループ本体を16個にします」 麺「…それは自動化できるのでは?」 w「できると思います」 麺「ではなぜ自動化しないのですか…」 w「さあ…なぜなんでしょうか…」 麺「…えーと、他には?」 w「関数を見つけたらinline修飾子を付けます」 麺「それで…?」 w「え….cから.hに移動する…とか…?」 麺「それで…?」 w「…」
それで…? _
僕も明日からレールの上でルビー動かすような感じに生きていきたい所存であります!!!! _
_ installkernelの引数は手で入力しないでいい
なんてこった!make installでいける!もう3年くらい勘違いしてた! _
この日記ツール糞か!$の半角が入力できん! _
なんかWindowsでスリープに入ったあと、Linux起動するとイーサ変っぽいな… _
_ quilt
quiltはパッチ管理するツールということでいいだろうか _
https://savannah.nongnu.org/projects/quilt _
バージョン管理みたいなことをパッチだけでできるというツール _
バージョン管理ツール使えよ…って話だが、バージョン管理には無いquiltの利点として、とりあえず僕が思い付くのは、データベースがテキストだということだろうか。 _
あと、ちょろっとメタデータがあるけど、これもただのリストとオリジナルのコピーなので、とりあえずfindとcatだけで内容が見れる。 _
今日までややこしそうと思っててあんまり見なかったんだけど、よく見るとこれ僕の好みっぽい構造だな。 _
詳しくは、このへん(PDF)を読んでもらうとして、(こうして人に勧めておいて自分は読んでないドキュメントが増えるのだった)適当に使いかただけ。 _
$ ls Makefile a.c b.c $ cat Makefile all: exe exe: a.o b.o gcc -o $@ $^n clean: rm *.o exe * $ cat a.c int main() { b(); } $ cat b.c int b() {}
こんな感じのディレクトリがあるとする。この状態で、 _
$ quilt new add-factor.diff
とする。これで新しくパッチを作る。 _
んで、編集したいファイルをadd _
$ quilt add b.c
もしくは、直接ちょろっとエディタで開いて編集するだけなら、 _
$ quilt edit b.c
とすると、addして、EDITORで開いてくれる。 _
んで適当に編集。 _
$ quilt diff Index: q/b.c =================================================================== --- q.orig/b.c +++ q/b.c @@ -1 +1,7 @@ +int fac(int i) +{ + if (i==0) + return 1; + return fac(i-1)*i; +} int b() {}
とすると、差分が確認できるはず。 _
$ quilt refresh
refresh すると、上の差分のパッチができる。 _
もう一個パッチを作る _
$ quilt new hello.diff $ quilt edit a.c $ quilt diff Index: q/a.c =================================================================== --- q.orig/a.c +++ q/a.c @@ -1 +1,2 @@ -int main() { b(); } +void hello() { puts("hello"); } +int main() { hello(); b(); }
新しくパッチを作って編集。 _
んで、popでパッチを取り消せる _
$ quilt pop
これでadd-factor.diffだけが当てられた状態になる。 _
もう一個パッチ作成 _
$ quilt new call-factor.diff
これで、add-factor.diffとhello.diffの間に、call-factor.diffを入れられる。 _
$ quilt edit b.c $ quilt diff Index: q/b.c =================================================================== --- q.orig/b.c +++ q/b.c @@ -4,4 +4,4 @@ int fac(int i) return 1; return fac(i-1)*i; } -int b() {} +int b() { fac(30); } $ quilt refresh
んで、push、popなどすればパッチを当てている状態を簡単に切りかえられる _
$ quilt pop -a # 全パッチはずす $ quilt push # add-factor.diff適用 $ quilt push # call-factor.diff適用 $ quilt push # hello.diff適用 $ quilt pop 2 # hello.diff call-factor.diff はずす $ quilt push -a # 全パッチ適用
大体こんな感じ。あと、野良パッチを適用するのはfoldとかで。 _
データベースが非常に簡単な構造になってて、patches/seriesに、パッチのリストが書いてあり、.pc/以下にパッチごとのオリジナルのコピーと、どのパッチを適用しているかを書いてあるapplied-patchesがあって、あと、quiltのデータベースのバージョン(多分)が書いてある.versionがあって、以上。 _
という、もはやシェルスクリプトでなんとかなんじゃねーの、っていうぐらいというか、実際シェルスクリプトで書いてある。 _
問題はドキュメントが無い。上のPDFとmanぐらい。けどシェルスクリプトだからソース見りゃいいか…というかmanがあるのにドキュメントが無いっていう考えが素敵だな。ぐーるるでけんせくできないものはどくめんとじゃない!!! _
というか、ドキュメントが無い…という考えかたが間違いか。manだけで記述できるくらい仕様がシンプルだというほうが正しいな。 _
_ FSIJ
今年はGCC行き忘れるという失態を犯してしまったのでメモ。これは行く _