憂鬱な午後のひととき


5月30日_
最近は朝6時前後に8~10km走ってるのだけど雨なら駄目. 3日走らないと1500kcalぐらい消費しないことになるのか. 2食分ぐらい? そのときは食べる量減らさないといかんな.
5月29日_

整数a, b (a < b)が与えられたときに区間[a, b) = {a+1, a+2, ..., b-1}にある整数の個数はb - a個. 1ずつではなくs個ずつ増える場合は(b - a + s - 1) / s個. では

int n = (b - a + s - 1) / s;

としたときの問題点を考えてみよう. まず符号付き整数の加減算の結果がその整数の型で表現できる最大の値(INT_MAX),最小の値(INT_MIN)を超えると処理系依存になることに注意する.
# 符号無しの場合は結果がモジュロされるので処理系依存にはならない.
以前書いたが, 符号付き数値の負の値の右シフトも処理系依存. とりあえず符号付き数値の扱いは注意が必要.

sizeof(int) = 4, INT_MAX = 0x7fffffffの処理系を考えてみよう. すると上の式はたとえばb = 0x7fffffff, a = 0, s = 2のときb - a + s - 1は途中でINT_MAXを超えるので処理系依存. 途中で + sをやめて式の外に出して, 代わりに最後に + 1してみよう.

int n = (b - a - 1) / s + 1;

とするとこれなら大丈夫だろうか.
いや, b = 0x7fffffff, a = INT_MINのときやはり途中結果が超えるのでアウト.
ただし処理系依存ではあるが, x86/x64をターゲットにしたC/C++コンパイラの場合, 大抵は演算結果を符号無しにキャストすれば大丈夫.

unsigned int n = (unsigned int)(b - a - 1) / s + 1;

さてステップsが負で整数がaがbよりも大きいときにも拡張してみよう. 区間(b, a]の中に a + s i(i = 0, 1, ...)の形の整数がいくつあるかということとする. つまり

n = #{x | x = a + s i, i = 0, 1, 2, ..., b < x };

この場合は

unsigned int n = (unsigned int)(a - b - 1) / (-s) + 1;

となる. 二つをくっつけて

unsigned int n = ((unsigned int)abs(a - b) - 1) / abs(s) + 1;

にするとよいだろうか.
a = bの時はn = 0になるべきだし, a > bかつs > 0のときは1になるべきだろう. こういうのは無理してくっつけるべきではないと思う.
さてs = 0の時は計算できないのでエラーにするとして

unsigned int f(int a, int b, int s)
{
    assert(s);
    if (a == b) return 0;
    if (a < b && s > 0) {
        return (unsigned int)(b - a - 1) / s + 1;
    } else if (a > b && s < 0) {
        return (unsigned int)(a - b - 1) / (-s) + 1;
    }
    return 1;
}

で全部をカバーしただろうか.

実は-sが危ない. s = -2147483648に対して-sはintとして正の値にはならない. つまり一般に標準ライブラリabs(x)はその値に対しては未定義だ.
ただ今回に限ってはその後符号無しに変換してるので結果的には動作する. もちろん処理系依存だし, s = -2147483648でないときも上記のコードは処理系依存なので要注意.

INT32-C. 符号付き整数演算がオーバーフローを引き起こさないことを保証する」も参考になる.

5月28日_
電子情報通信学会の総会に参加
英文誌の論文賞を戴く. 推薦してくださった方, どうもありがとうございます. 会が想像以上にフォーマルだったのでびっくり. 岡本龍明先生に「スーツ着てないの君だけだねえ. まあ君らしいけど」と言われてしまった. 穴があったら入りたい.
帰り, 知人に勧められた八天堂のクリームパンというのを買ってみる. 抹茶は売り切れだったのでカスタードと小倉. 明日食べてみよう.
5月27日_
gdbで楽するために.gdbinitに書いてるいくつかの設定
私は出来るならVisual Studioのデバッガを使いたいけど, まあgdbも使うときもあるよねということで.
typeしたコマンドの履歴は残したい.
set history save on
set history size 10000
set history filename ~/.gdb_history
C++や構造体を見やすく. アセンブリ言語レベルで追いかけたい. 表示をIntel形式にしたい.
set print pretty on
set print asm-demangle on
set print demangle on
set disassembly-flavor intel
set print symbol-filename on
Xbyakなどで生成したコードに突入するとdisasコマンド入力しても
(gdb) disas
No function contains program counter for selected frame.
みたいに文句言われる. そういうときはeipで範囲指定すればいい.
disas $eip $eip+32
gdbの新しめのだと
disas $eip,+32
で$eipから32byteの範囲を指定することもできる.
define jit
    if sizeof(void*) == 8
      disassemble $rip,+32
    else
      disassemble $eip $eip+32
    end
end
みたいにしておくと[jit]ってするだけで表示できて便利だ(名前は好きなように). レジスタ表示も
define reg
    if sizeof(void*) == 8
        printf "rax:%016x rbx:%016x rcx:%016x rdx:%016x\nrdi:%016x rsi:%016x rbp:%016x rsp:%016x\n", $eax, $ebx, $ecx, $edx, $edi, $esi, $ebp, $esp
        printf " r8:%016x  r9:%016x r10:%016x r11:%016x\nr12:%016x r13:%016x r14:%016x r15:%016x\n", $r8, $r9, $r10, $r11, $r12, $r13, $r14, $r15
    else
        printf "eax:%08x ebx:%08x ecx:%08x edx:%08x\nedi:%08x esi:%08x ebp:%08x esp:%08x\n", $eax, $ebx, $ecx, $edx, $edi, $esi, $ebp, $esp
    end
end
とやってreg[return]で. おっとそもそもデフォルトではsiしても何のニーモニックを実行してるか分からないのであった. アセンブリ言語で追いかけたい時用の設定ファイルを作っておいて(たとえば.gdbasmとか)その中に
display/i $pc
と書いておいて.gdbinitに
define asm
    source ~/.gdbasm
end
ってすると[asm]で設定を読み込めて便利だ.
# display設定してないとき
(gdb) si
0x08048975      15              Code c;
(gdb)
0x08048978      15              Code c;
(gdb)
Code (this=0xbfaf238c) at t.cpp:5
5               Code()
# display設定したとき
(gdb) si
0x08048975      15              Code c;
1: x/i $pc
0x8048975 <main+17 at t.cpp:15>: mov  DWORD PTR [esp],eax
(gdb)
0x08048978      15              Code c;
1: x/i $pc
0x8048978 <main+20 at t.cpp:15>: call 0x804b044 <Code at t.cpp:5>
(gdb)
Code (this=0xbfc581ac) at t.cpp:5
5月26日_
・数論暗号勉強会参加の後, 少しの時間神保町で古本屋めぐり. 懐かしい本がいっぱい.
・(同僚ではない)知り合いが転職するので送別会. 最初はどこの会社に行くのとかそういう話だったのに, いつの間にかコードレビューの重要性の話やgitを社内に普及させようと思ってる人の熱い語りや別の人によるgitのbranchの素晴らしさは認めつつ如何にインタフェースが腐ってるかの話で終わった. あれ, 何の会だったっけ.
5月25日_
sinya8282さんの勉強したてのC++コードにコードレビューで駄目出ししまくると, みるみるよくなってる. 素晴らしい. ていうかコード書くの速いなあ. 目標はLLVMはもちろんgccの静的コンパイル結果を超えることやね.
5月23日_

下の答え:

3番目のどちらも同じが正しい. 規格的にはそれで終了. ただWindowsやLinuxではそれ以外の部分で違いがある.

ファイルサイズを見てみよう. まず32bit Windows + VC9で見ると(A)は5632byte. (B)は, と始めると何やらうちの古いマシンのHDDが唸り出し, ビルドに時間がかかる. 結果は536876544(約512MB). うぎょ.

Linux + gcc(オプション無し)で見ると(A)は7484byte. (B)は536878412byte(約512MB)と挙動がほぼ同じ. 生成されたバイナリをobjdump -tで見てみると

// (A)
080495e0 l     O .bss   20000000              buf

// (B)
080495c0 g     O .data  20000000              buf

と置かれている領域が異なる. .data領域はそこにそのままデータを配置するので実行ファイルのサイズに直結する. .bssはOSや実行ファイルのローダが適切に0に初期化することで実行ファイルのサイズにあまり影響は与えないということでした.

Project Eulerなどで素数列のために巨大な配列を一つ作って操作することはよくあるけどそういうときは(A)のようにした方がいい. それから組み込み系のコンパイラによっては.bss領域が0初期化されるとは限らない仕様になってたりすることもあるので注意.

5月22日_
ちょっとしたクイズ. 次の二つのコードの差は何か.
// (A)
static int buf[1024 * 1024 * 128];

int main()
{
    buf[0] = 1;
    buf[1] = 3;
    buf[2] = 9;
    /* ここから */
}
// (B)
static int buf[1024 * 1024 * 128] = { 1, 3, 9 };
int main()
{
    /* ここから */
}
答えの選択枝?
  1. a[3]以降が0に初期化されているのは(A)で(B)はそうとは限らない
  2. a[3]以降が0に初期化されているのは(B)で(A)はそうとは限らない
  3. 両方ともa[3]以降は0に初期化されている
5月21日_
久しぶりに肩が凝ってしまったので整骨院で首の調整をしてもらう. まだ多少ずれてるらしい. ちょっとずつ気長にやるしかないのかな.
5月20日_
JANTのオーガナイズド・セッションの講演者募集MLを出す. 間違ってないか冷や冷やだなあ.
5月19日_
『詩羽のいる街』(山本弘)
かなり楽しめた. 他人同士が必要としてるものを結びつけることで, 自身はお金を使わず生活しているヒロイン. ライトのベルネタは分からないのも多い(大半?)だけど作中作もかなり出来がよい. アニメを利用した村おこしのシーンやいたずらを繰り返す人を追求する推理小説っぽいところなどのいろんな仕掛けもよい. ファンタジーといいつつ自分の街だけでもよくしておこうというところで, ぎりぎりそういうのがあってもよさそうと思えてしまう.
5月18日_
事務手続きのための調べ物をいろいろしつつ, コードレビューをざくっりと.
5月17日_
C++0x総復習
wraith13さんによるC++0xのサーベイ. 力作. タイトル, 総復習というよりは予習という気はするが(C++な人にとっては既に復習なのか).
5月16日_
『がっちりマンデー』(TBS)
スゴイ人が選ぶスゴイ人という企画がおもしろい. おとといのは東大阪区に行ってスゴイ職人さんを探していた. ここは日本で一番工場の密度が高いところらしい. プログラマでこういうのやったら一般の人にも分かりやすいかも, と西尾さんに話したら「物凄く速くキーボードを叩ける」以外は絵になりそうにないから駄目だろうとのこと. せやね. ちと残念. 雑誌では昔『オープンソースマガジン』で「ハッカー養成塾」というリレー記事があったなあ(首藤さんのハック教を切り刻め).
5月15日_

原子力発電はいま』(プロジェクトB)

図書館でなんとなく手を取って奥付を見ると1989年発行. 当時はどういう状況だったのだろうと読んでみた. まんが内では肯定派と反対派と, そのどちらか正しいのか分からなくて悩む人が出てくる. チェルノブイリの事故の後なので, そこから漏れた放射性物質により汚染された食べ物を心配する主婦もいる. どれが正しいと結論づけてないところがいい.

何重にも防御システムを考えていて安全と思ってたのに駄目だったのは現状の通り. かと言って, 火力は石油の問題があるし, 他のクリーンエネルギーはまだまだなのは今でもあんまし変わってない.

まんがの中で反対派が「スウェーデンは2010年までに原発全廃を決めたのを日本を見倣わなければならない」, 反対派は「そんなの難しい, 90年代には見直しもあるだろう」という感じのシーン(うろ覚え)があった. ほう, では今はどうなってるのだろうと見てみるとなぜスウェーデンは原子力政策を「転換」したのか?という記事があった.

1980年に2010年までに全廃決定, 1997年に期限を撤回, 2010年立て替え承認という経緯だけを見ると原発全廃は難しくて方向転換してるように見えるけど, そうじゃないと主張されている. もちろんその反対に解釈する記事もある(スウェーデンが選ぶ 脱「脱原子力」).

いずれにせよ30年前から脱原発を進めてきたスウェーデンですら困難なのだから, 今から日本が舵を切るのは相当難しいのだろう. 改めて地道な改良の得意な日本の技術力に期待したい.

5月14日_
タイムスクープハンター』(NHK)
タイムスクープという未来の会社から過去に派遣された人が遭遇した話をドキュメンタリーにしたという設定の歴史番組. 初めて見た. 今回は平安時代に対馬で海を監視し, 海賊船や貿易船をみたらのろしをあげる命を受けた民に密着取材する話. のろしをあげると, いくつかののろし中継地点を経て太宰府に送られる.24時間2交替制で非常に過酷.見誤った場合の罰則も厳しい.
民のしゃべる言葉が今の日本語を違ってたり, 海賊たちとの戦いのシーンも緊迫しててすごかった. 国銅という小説もそうだったけど, 有名ではない一般の歴史人物に焦点を当てたものというのがいいなあ.
5月13日_

そういやboost::irangeのテストはどうしてるんだと思ってみてみたら, テストコードに

BOOST_ASSERT( (last - first) % step_size == 0 );

なんて入ってて下記(C)パターンのテストができない. つまりそんな状況は考えてない, 排除してるってことだ(ほんまかいな).

それはともかく, boost::irangeをBoost.Parameterに対応の記事で初めてboost::irangeを知って 「これは凄い, 使ってみよう」と思った人はやめた方がいい. 見た目に騙されてないで, irange(0, 10, 3)の結果に9が入ってないのがおかしくないかと思える程度の注意力は欲しい(とえらそうなことを言う).
# 私は以前からこの挙動を知ってたので自分が知らなかったときに気づけたかどうかはわからん. ただ, 現状ではそもそも(step = 1でも)使いたいとは思わないけどね.

5月12日_
boost::irangeのstepは設定できてはいけない.
#include <iostream>
#include <boost/range/irange.hpp>

int main()
{
    std::cout << boost::irange(0, 10) << std::endl;

    std::cout << boost::irange(0, 10, 2) << std::endl;
    std::cout << boost::irange(0, 9, 2) << std::endl;
}
// 結果
0123456789 ; (A)
02468 ; (B)
0246 ; (C)
(A), (B)の結果を見れば大抵(C)は02468を期待する. だって普通(C)は
for (int i = 0; i < 9; i += 2)
と等価なものを生成すると思うだろう. たとえばPythonなら端は含まないので
>>> print range(0,10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print range(0,10,2)
[0, 2, 4, 6, 8]
>>> print range(0,9,2)
[0, 2, 4, 6, 8]
Haskellなら端は含むので
Prelude> [0..10]
[0,1,2,3,4,5,6,7,8,9,10]
Prelude> [0,2..10]
[0,2,4,6,8,10]
Prelude> [0,2..9]
[0,2,4,6,8]
どちらも首尾一貫しているのに対してboost::irangeのstep数が1より大きいときの挙動はそのどちらでもない. そんなパラメータ設定は気を付けて使うのではなく, 禁止されるべき.
いや, もちろん首尾一貫するよう仕様を変更すべきというのでもよい. というか単にバグなのか?
5月11日_
PRML4章読み. 分からなかったらとなりのshuyoさんに聞けるありがたさ. 数学の部分は別にたいしたことないのだけど用語や仮定がね.
ここまできて漸く序論の「推論と決定」の生成モデルや識別モデルの話を理解できたように思う. パーセプトロンは私の中ではこないだのtokyoNLPのsleepy_yoshiさんの黒歴史(?)とセットになってしまったやつだ.
p.181の(凸領域が)「常に1つに連結していて」って変な日本語だなあ. 原文はsimply connectedだったのだろうか. ここは「常に単連結で」といいたい.
5月6日_
・部外者だけど首藤研のいつもの懇親会に行ってみた.
首藤さんは産総研やベンチャーにいたあと准教授になられてるので, プログラマやってるだけじゃ見えにくい, お金や会社に関するお話も面白い.
・先月variadic templateとinitializer_list どちらがよいのかなと試してみたときに派生して見つけた VCのx64での最適化がおかしい件はバグとして将来のバージョンで修正してもらえることになった.
現状で無理やり最適化させるワークアラウンドがよく見つけたなという変なやつ. ループアンロールさせるための各種の条件のうち一つにヒットさせるためなのだろうけど, ループ内でグローバルなfloat変数をいじるなんてどうみても最適化が阻害させそうなのに.
# 注意, これはあくまで定数配列に対するコードが(たまたま)よくなるだけで普通のループは遅くなるので使ってはいけない.
float g_dummyFloat; // 下の関数を最適化させるための使わない変数
template<class T, size_t N>
T my_max(const T (&x)[N])
{
    float dummy = g_dummyFloat;
    T m = x[0];
    for (size_t i = 1; i < N; i++) {
        g_dummyFloat *= 2.0f; // 無駄に計算させてみる
        if (x[i] > m) m = x[i];
    }
    // その値は使わない
    g_dummyFloat = dummy;
    return m;
}

int main()
{
    const int a[] = { 1, 9, 5, 3 };
    return my_max(a);
}
---
main PROC
   mov eax, 9
   ret
main ENDP
5月4日_
「頭がしびれるテレビ」神はπに何を隠したのか
期待外れ. というか期待はしていなかったという意味では予想通りか. 数学史に焦点を当てるならそれはそれで構わないが, 頭がしびれることをするなら, たけしのコマネチ大学みたいな実際に考えることをせなあかんだろう.
ビュホンの針やマーダヴァ-ライプニッツ級数も3.1程度でπが現れたなんて無茶. 強引すぎて逆に科学じゃない. せめて大科学実験的に3.14ぐらいまでは出したい.
5月2日_
・査読もう一つ終了. と思ったらまだ先だけど9月にちょっとすること発生.
・会社で今日の午後から13.5連休の人がいた.
だんご庄のだんごか, 筍亭のたけのこか, 半兵衛麸か奈良の懐石か何か食べたい.

御意見は光成滋生<herumi@nifty.com>までお願いします