憂鬱な午後のひととき


10月30日_
・500GBのHDDに500GBのファイルを置いて消す場合(ext2), rmだと12分近くかかった. 再フォーマットなら3分ぐらいですんだが, ちと乱暴すぎる. 何かいい方法はないだろうか.
・また料金の一部を改定したらしい. いっその事「時価」にしたらどうだろう. 流出が多ければ高く, 流入が多ければ安く. 名付けて利益定額サービス.
10月28日_
ソフトバンクモバイル契約手続き一時停止
人間じゃなくてシステムだけど, 大丈夫じゃなかったのね.
10月26日_
夏に引っ越して以来, KDDIのADSLを使ってるのだが, 領収書統合や, webでの閲覧サービスに変更しようとすると, なんとも分かりにくいページが多くて困る. 受付番号, 契約コード, サービスIDと似たようなものが多いし, セルフページのパスワードや初期パスワードやauのパスワードなどもあって何がなんだか. 構成もKDDIやauやDIONのページをあっちこっちたらい回しされる感じ. そもそも契約時にやってきた説明書が細かい字でびっしり10ページ以上あり, その中に関係ない料金の説明も入ってるのも問題(その証拠に電話で聞いたら最初オペレータも間違えた. 基本プランなのに!). KDDIでこれなんだから, あの日替わりプランを打ち出したSoftBankは大丈夫なんだろうか.
10月24日_
『言語を生みだす本能』(スティーブン・ピンカー著 椋田直子訳)
母国語が思考を枠づけるという考え(言語決定論というそうな)に反対し, 人は普遍的な心の中の言葉で思考する(言語本能説)を主張する話. なかなか面白そうなトピック. ただ, まだ上巻しか読んでないのに言うのもなんだが非常に読みづらい. 話があっちこっちに行ったり, 無駄に細かい話になったり, 想定読者のぶれが大きいように思える説明が多い. たかが複文の概念に何ページにも渡って説明したり, 突如マルコフモデルがでたり. そのくせ再帰という用語はずっと後にならないと出ない. 日本科学未来館の説明文なみに分かりにくい. まあ, それはともかく内容についても疑問が出るところが.
音声の仕組みで舌の位置に関して, 「自分に近いことを示す単語は舌を前方高く置く母音を使う傾向がある」という話題が出る. つまりは「you」よりは「me」の方が舌が前というわけだ. それはそうだが, それに続けて「there and here」とは言わず「here and there」だとかそういう例を出して, 「自分が先行, 人間の精神は単語の順序を規定する」とまでいう.
日本語ならたとえば「きみ」と「ぼく」だと舌の位置はむしろ逆だし, 「あちらこちら」とも「ここかしこ」とも言うから反例はいくらでもあげられるだろう.
母国語に思考は左右されないというなら, 英語だけで結論を出すのはどうか.
10月21日_
支払い能力はあるのに「義務教育だから子どもの給食費を払わない」という親がいるそうな. 「義務教育」って「親が子どもに教育を受けさせる義務がある」って意味なんだし, 無償なのは普通授業料だけなのだから, なんでそんなこと言うかな.
10月19日_
BBSにてお題が一つ. 次の関数にある3個の条件比較を無くせ.
bool org(int x)
{
    static bool s = false;
    static int p = -1;
    assert(x < 32);
    if (x == p) {
        s = !s;
    } else {
        s = (x == 1 || x == 4);
        p = x;
    }
    return s;
}
要は前回と同じ値なら, 前回と反対の真偽値を, そうでなければ1か4のときのみtrueを返せというもの(ここでは問題自体の是非は問わない). 小次郎さんによる現在の最善解は
/*
    @retval 0 if false
    @retval !0 if true
*/
int ans1(int x)
{
    static const uint32 D = (1 << 4) | (1 << 1);
    static uint32 s = D;
    uint32 m = 1 << x;
    uint32 r = s & m;
    s = ~r & (D | m);
    return r;
}
なんと, わずか5個のビット演算. 感心する点は二つ. 一つはオリジナルの(x == 1 || x == 4)のところの特殊値の比較が増えても演算量は変わらない点. もう一つは前回の真偽値と位置の二つのstatic変数を一つですませた点. お見事.
10月18日_
原子番号118の原子核ができたそうな. 命名規則からウンウンオクチウム(1=ウン, 8=オクト). 原子番号111だとウンウンウニウム. なんか面白すぎ. そういや昔, ろうそくの成分の一つにエイコサン(C20H42)というのがあるから, 「披露宴のキャンドルサービスで『エイコサンが燃えてるよ』というとロマンチックだ」って書いてある本があったが, 99%ひかれると思う.
10月15日_
AENという店に行ってみた. 野菜中心で, でも肉や魚料理もあってとてもおいしかった. スタッフの対応もよかったし. 久しぶりにほっとした感じ.
・数日前から何かの拍子にcsrss.exeが1GBのメモリを消費するようになり困っていたのだが, 犯人はコマンドプロンプトであることが分かった. 「でも何故それを起動するだけで?」と思っていたら 画面バッファのサイズがいつのまにか9999(W)x9999(H)になっていた. 幅を80にしたら問題なくなって一安心. 履歴バッファは必要になってから確保するのではなく予めとっておく方式やったんか.
10月13日_
恐ろしく眠たくなる季節になった? 夕御飯を食べてる最中から眠くて仕方ない.
10月9日_
『個人のたたかい 金子光晴の詩と真実』(茨木のり子)
自由奔放な一生だったんやね.
金子光晴がもっともたいせつにしたのは「個人」というものでした。 国家権力にも強制された思想にも、そっぽをむいて、 「自分自身の頭で考える、自分自身のからだで感じとる」という根本の権利を、 なにものにもゆずりわたそうとしませんでした。
これはごくあたりまえで、単純なことのようにみえますが、日本人にとって、 もっともにがてなことなのでした。
歴史をふりかえってみれば、その時々の権力に、 思考力まであずけっぱなしという例はいくつもみつけだすことができるでしょう。
10月8日_
秩父の芦ケ久保駅から円山にハイキング. 距離は11kmちょいと短めの割にアップダウンが激しく結構足にきた. 天気がよく素晴らしい青空. ただ前日の雨のせいでか水流が多く, 道が途切れていた箇所もあって少々びっくり.
10月6日_
スルー力カンファレンス[いやなブログ]
やあ, やられました. 「スルー力なんて初めて聞いた」と思わずぽちっとなと事前仮登録ボタンを押してしまいました. ただ普段はjavascriptを切ってるため何も起こらずそのままスルー. 種明かしの後ソースを見て分かるというおまぬけさ. しかし, スラッシュドットを見ると怒ってる人もいるみたいで. 洒落に怒っても仕方ないのになあ.
10月3日_
The Aggregate Magic Algorithms [Radium Software Development経由]
ざっと見た感じ殆ど知ってるものばかりっぽいけど, 使えそうなのあるかな.
・『第六大陸』(小川一水)
前回読んだのがよかったので. 数十年先に月に基地を造るならどうするかを丹念に追いかけるSF. テンポがゆったりで中盤(私が)ややだれてしまったけど力作. 海の底から始まる導入部はうまい. ロケット開発者たちの心意気は『ふわふわの泉』を連想した. 日本の明るい未来を想定しているところがちょっと嬉しく, またそうなって欲しい(最近の状況を見ると不安だが…). 個人的にうけたのが1巻300頁の
八つの惑星すべてと冥王星の素顔を撮影し
3年前の本なのに何故か冥王星が別枠. 恐るべし.
10月2日_
↓答えに至った思考(試行)の流れ(ダイジェスト --- ちなみに極めて帰納的)
元の式は分岐だらけ → 速くするなら(答えが存在するなら)ループを消すしかない → 具体例を見ると値は対数的なのでどこかで ilog2(x) = [log2 x] を使うはず.
という思惑の元, とっつきやすそうな斜辺の所を抜き出してみました.
i            0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
calc(i+1, i) 0 0 1 0 2 1 3 0 4 2  5  1  6  3  7  0  8  4  9  2 10  5
これを見ると2巾のところは半分です. それ以外でも2で割るとよいところがちらほら. これは偶然ではないだろうといくつシフトすればなるのか調べてみました.
i            0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
calc(i+1, i) 0 0 1 0 2 1 3 0 4 2  5  1  6  3  7  0  8  4  9  2 10  5
シフト数     1 2 1 3 1 2 1 4 1 2  1  3  1  2  1  5  1  2  1  3  1  2
お, 扱い易そうな数値が出てきています. 一つ置きに1. これは一体なんだろう.
暫く悩んで" i を2進数表記したとき下から0が並んだ個数 + 1"に一致することに気がつきました(うひょ).
    i 0の数  +1
00001   0    1
00010   1    2
00011   0    1
00100   2    3
00101   0    1
00110   1    2
00111   0    1
01000   3    4
01001   0    1
01010   1    2
01011   0    1
01100   2    3
01101   0    1
01110   1    2
01111   0    1
10000   4    5
どんぴしゃです. さて下から並んだ0の数の数え方ですが, これは定石があります. 0が並んでいるところから1を引くとその部分は繰り下がって全て1になり, それは初めて1があるところまで続きます. 従ってそれらを xor すると, 初めて1がたつところより大きいところは消えるのです.
               ┌下から見て初めての1
               v
 x     = ? ? ? 1 0 0 ... 0 0        ; ? は 0 または 1
 x - 1 = ? ? ? 0 1 1 ... 1 1
 ---------------------------
x^(x-1)= 0 0 0 1 1 1 ... 1 1
ここで 2 を底とした対数関数を越えない最大の数を返す関数 [log2 x] が登場します. 大昔書きましたが, x を浮動小数で表すと指数部 e - 127 がまさにそれを表します. x = 2e - 127 1.f とすると
bit |31|30  23|22    0|
x = |s |   e  |   f   |
だから, それは下に書いたように
int ilog2(unsigned int x)
{
    float a = (float)x;
    return (*(unsigned int*)&a >> 23) - 127;
}
となるわけです. これで斜辺のときはうまく行きました. ここまでくればこれを2次元に拡張するのは(幸い)容易です.
10月1日_
クイズの答え
小次郎さんの
int FindBit(unsigned int x)
{
    if (x == 0) { return 0; }
    unsigned int y;
    int n = 1;
    y = x & 0xffff0000; if (y != 0) { x = y; n += 16; }
    y = x & 0xff00ff00; if (y != 0) { x = y; n += 8; }
    y = x & 0xf0f0f0f0; if (y != 0) { x = y; n += 4; }
    y = x & 0xcccccccc; if (y != 0) { x = y; n += 2; }
    y = x & 0xaaaaaaaa; if (y != 0) { x = y; n += 1; }
    return n;
}
はビット長 + 1を求めているので x == 0 を除いては bsr + 1 と同じです.
int FindBit2(unsigned int x)
{
    if (x == 0) return 0;
    __asm {
        bsr eax, x
        inc eax
    }
}
Cの範囲で記述するなら s < 22 という制限の元では
int FindBit3(unsigned int x)
{
    if (x == 0) return 0;
    float a = (float)x;
    return (*(int*)&a >> 23) - 126;
}
という処理もあります. FPUレジスタをいじってよいなら
    _controlfp(_RC_DOWN, _MCW_RC);
と丸め処理を切り捨てモードにすることで(Linuxなら_FPU_SETCW())上記の s の制限をとることもできます. 単独なら bsr が最適解とおもいますが, FindBit3はSSE2を使えばメモリを介さず複数個同時処理できるのでこっちの方がよいと思います. dskさんのテーブル引き(FindBit4)はアドレスが決まるまでテーブル引きができない場所が続いてしまうので今回のケースでは遅くなるようです.
    int x = 0x1234567;
    int sum = 0;
    int begin = clock();
    for (i = 0; i < 100000000; i++) {
        unsigned int y = x;// & ((1<<25) - 1);
        sum += FindBit(y);
        x *= x + 0x12345;
    }
で実行時間を測ってみると(@P4D 2.8GHz + VC2005), 1~4で1.92, 0.47, 1.33, 18.08(単位:sec)でした.
ちなみに私の答えは s < 22 の仮定の元で
int ilog2(unsigned int x)
{
#ifdef WIN32
    __asm {
        bsr eax, x
    }
#else
    float a = (float)x;
    return (*(unsigned int*)&a >> 23) - 127;
#endif
}
int calc(int a, int b, int s)
{
    return b >> (ilog2(b ^ a) + 1);
}
でした(a != bなので x != 0 も仮定できる). 面白いことに s に依存してません. FindBit()の引数が異なるのですが結果は同じっぽいですね. 何故だろう.

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