憂鬱な午後のひととき


11月28日_

『ハルさん』(藤野恵美)

頼りない人形作家の父とその娘の成長を描くほのぼのミステリ. が, ちょっと期待外れ.

16年経過してるのにお父さんが全然進歩してない. 「日常の謎」としても大分弱い. ミステリという枠に無理やり入れないほうがいいんじゃないか. 「…」の多用も目障りだった.

11月26日_

copyコンストラクタや代入演算子

暗号で使う実体が固定長配列であるような基本整数型の場合, 下手に実装しちゃうより何も書かない方がコンパイラがよきに計らってうまくいくことが多そうだ.

VCがintrinsicを展開してくれない問題は, Microsoftに聞いたら次のバーションで改良してくれるらしい.

11月25日_

東京ステーションホテルのパーティー

受賞者の方にお招き頂き参加する. すばらしい賞の受賞おめでとうございます.

ネクタイを結ぶのが久しぶりでなかなかうまくできない. 着ていくスーツがなくて困った.

11月21日_

『147ヘルツの警鐘 法医昆虫学捜査官』(川瀬七緒)

冒頭, かなり気持ちの悪い描写で猟奇ミステリかと思ったらそうじゃなかった. 虫の性質を利用して捜査を行う学者の話で非常に面白い. ある虫の性質を利用して死亡時刻を推定していくあたりはすごい.

自由奔放な女性の学者は突飛な行動はするけれども, そういうキャラクターにありがちな傲慢さは少なく悩んだりもするのもよい. これはシリーズ化したらしいなあ, と思ったら出ていた.

11月19日_

HaswellのBMI1, BMI2の命令

mulxやbzhi, shrxなど結構面白い. shldも(add/adcの組み合わせより)意外と速くていろんなパターンの組み合わせが作れて速度も結構変動する.

パズルチックで最適化にはまってしまう.

11月18日_

VCでSIMDのintrinsicを使うとループをアンロールしてくれない

ラボユースの対応で, あるコードがいまいち期待したコード生成をしていないのでいろいろ調べたら, VCのintrinscはとても簡単なループを展開してくれないことが分かった.

__m128i f(__m128i x)
{
    for (int i = 0; i < 4; i++) {
        x = _mm_add_epi32(x, x);
    }
    return x;
}
    mov     eax, 4
.lp:
    movdqa  xmm0, XMMWORD PTR [rcx]
    paddd   xmm0, xmm0
    movdqa  XMMWORD PTR [rcx], xmm0
    dec     rax
    jne     .lp
    ret

最適化オプションは/Ox /Ob2 /GS- /Qpar. 今更だけどこれはちょっと困る. というか「えっ, 何で?」というレベルなんだがVC2013でも同じだった.

ちなみにループで毎回メモリに値を保存しているのはWindowsのデフォルトの呼び出し規約でxがポインタ渡しになり, その変数を使い回してるからのようだ. これは盲点.

VC2013から対応した/Gvオプション[VC2013で導入されたベクトル呼び出し規約 __vectorcall]を使うとちょっとましになる.

    mov     eax, 4
.lp:
    movdqa  xmm1, xmm0
    paddd   xmm1, xmm0
    movdqa  xmm0, xmm1
    dec     rax
    jne     .lp

でもやはり「何してるの?」というレベルなのには変わりない.

こんなに酷かったけなあと思いつつ, そういやetaTなんかを書いてたときはあまりループを使ってなかったかな. Loopテンプレートを使ったりしてたから気がつかなかったのか.

templateは可読性が悪いし, 今回はとりあえずループ回数8以下の固定値に制限してこんなマクロを作ってみようか.

#define LOOP(type, var, begin, end, express) \
{ \
    assert(end - begin <= 8); \
    type var = begin; \
    { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
    var++; \
    if (var < end) { express; } \
}
__m128i f(__m128i x)
{
    LOOP(size_t, i, 0, 4, (x = _mm_add_epi32(x, x)))
    return x;
}
movdqa  xmm0, XMMWORD PTR [rcx]
paddd   xmm0, xmm0
paddd   xmm0, xmm0
paddd   xmm0, xmm0
paddd   xmm0, xmm0
movdqa  XMMWORD PTR [rcx], xmm0
ret

まあ, 一応まともなコードが生成された.

11月15日_

__attribute__のつける位置

11日のところで関数のプロトタイプにしかつけられないと書いてましたが間違いでした. 定義にもかけます. ご指摘ありがとうございました.

11月14日_

↓AVX2版のfmath::expd_v

せっかく作ったのに, 「自分で書くから要らない. 資料が欲しい」と言われたw

11月13日_

『重力とは何か』(大栗博司)

とても面白い. 説明もうまい. 前半は自分でも勉強したり, 別の啓蒙書で読んだりした内容が多いけど後半は著者の研究の紹介や新しい結果などが紹介されていて新鮮. 正直, 重力のホログラフィー原理の付近は比喩であってもよくわからなかったけど.

機会があれば, もうちょっとちゃんと勉強してみたいな.

fmath::exp_ps256

何か海外の人からメールがあったのでAVX2版を作ってみた(たまーに問い合わせが(別々の人から)くる).

ベクトル版だとdoubleのexpの計算が6clkを切った(テーブルキャッシュがヒットしてること前提だけど). あと, gatherに頼ったのでそのあたりがんばったらもしかしたもう少し早くなるのかもしれない. しかしいい加減ヘッダにコード書くのやめてきれいにしないといかんな.

11月11日_

C++のメンバ関数でprintf型関数の型チェックを行う.

gccではprintf系の関数を使っているときに-Wformatをつけてコンパイルするとフォーマット文字列と引数の型の一致のチェックをしてくれる.

#include <stdio.h>
int main()
{
    printf("a=%d\n", 1.3);
}
>g++ t.cpp -Wformat
t.cpp:4:25: warning: format '%d' expects argument of type 'int',
  but argument 2 has type 'double' [-Wformat=]
     printf("a=%d\n", 1.3);

VCでは/W4にしても警告は出ないが, 実は/analyzeをつけると警告が出る.

c:\tmp>cl t.c /analyze
c:\tmp\t.c(15) : warning C6273: 整数でない値が _Param_(2) として渡されました。
'printf' への呼び出しには整数が必要です。実際の型: 'double': ポインター値を渡す場
合は、%p を使用してください。

ただ自作printf系の関数ではそれらのチェックは行われない. しかしgccでは__attribute__を使うとそういう関数でもチェックできる.

__attribute__((format(printf, フォーマット文字列の位置, 可変長引数の開始位置))という形で関数につける. 関数のプロトタイプにしかつけられないのでinline関数のときは注意する. 定義にもつけられました(11/15訂正).


#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
inline void myPrintf(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

VCでは_Printf_format_string_をfmtの前につければチェックできる. VCの方が関数の実装にも記述できるので便利である.

void myprintf(_Printf_format_string_ const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

ところでC++のメンバ関数で同様のことをする場合, VCの場合は何も考えなくてよいのだが gccの場合上記のままだと意味不明なコンパイルエラーになる.

struct X {
    __attribute__((format(printf, 1, 2)))
    inline void X::format(const char *format, ...)
    {
        va_list args;
        va_start(args, format);
        vprintf(format, args);
        va_end(args);
    }
};
>g++ t.cpp -Wformat
t.cpp:5:75: error: format string argument is not a string type
  void format(const char *format, ...) __attribute__((format(printf, 1, 2)));

いや, formatはどうみてもstring typeだろうとか. しばし悩んで気がついた. gccではクラスメソッドは第一引数に暗黙のthisが渡っていると考えると引数の位置に+1しないといけないんじゃないかと(cf C++のメンバ関数の呼び出し方法).

struct X {
    void format(const char *format, ...) __attribute__((format(printf, 2, 3)));
};

今までやったことなかったっけな. 気がつかなかった.

int main()
{
    X x;
    x.format("test=%d\n", 3.4);
}
t.cpp: In function 'int main()':
t.cpp:19:27: warning: format '%d' expects argument of type 'int',
  but argument 3 has type 'double' [-Wformat=]
  x.format("test=%d\n", 3.4);

警告も, argumentの位置がずれてるので気を付ける(3.4は2番目なのにargument 3になってる).

11月10日_

足首まであるスリッパ(?)

明け方プログラミングしてると体が凍えてしかたない(暖房器具が無い). 毛布にくるまったりしてるのだけど足元が寒い. どうしようかと思っていたら, たまたまルームブーツなるものを見かけた. 試着してみるとちょーあったかい. これはいいと購入. ちょっと歩きにくいが基本座ってるだけなので問題ない.

ついでではないが, ランニングシューズも踵がすり減って酷いので購入. 加湿器もネットで購入. 結構散財してしまった.

11月9日_

C++14規格レビュー勉強会#2の一般参加枠

前回と同じくサイボウズ・ラボでやる予定です. 興味のある方はどうぞ.

・加湿器, 今使ってるASK-233はメンテナンスが楽で気に入ってるのだけどスチーム式なので電気代がかかる. ぼちぼち違うタイプのを買おうかと調べていてびっくり. ASK-233は2年前にリコールになってた. 何も起きてなくてよかった.

11月6日_

新しい暗号技術が2万ビュー突破

してて驚いた. かなりの時間を使って資料をつくった甲斐があったな. これはもう『ネットワークセキュリティを支える技術』みたいな名前で本にするしかない???

11月5日_

球面にきれいな足し算の構造は入れられるのか

>球面は平面+無限遠点と1対1対応するわけで、これには加算の構造が入るように思うのですが

どうやって加算の構造をいれましょうか. 複素平面Cに無限遠点∞を足して球面S2とかくことにします(S2 = C ∪ {∞}).

Cには通常通りの加算が入ってるとしましょう. つまり a = x + yi, b = z + wi(iは虚数単位, x, y, z, w ∈ R(実数)) としたときa + b = (x + z) + (y + w)iとする.

さてS2が加法群となるようにa + ∞ for a ∈ C, ∞ + ∞の値が適切に定義できるか考えてみます.

もしa + ∞があるCの点bになったとするとa + ∞ = b. つまり∞ = b - a ∈ Cとなって矛盾. つまりa + ∞ = ∞と定義せざるをえません(*).

次に∞の逆元(-∞)が何に等しいか, つまり∞ + X = 0となるXについて考えます. (*)は∞にCのどんな点を足しても∞(≠0)になると言ってるのだから, 消去法でX = ∞となります. つまり∞ + ∞ = 0. そうすると(*)の両辺に∞を足すとa = 0となってしまい矛盾です.

これはCに普通の加算の構造を入れたまま球面にまで足し算の構造を拡張することはできないことを示しています.

じゃあ, 普通の加算の構造は諦めて, 別の構造を入れるとうまくいくじゃないかという疑問は, なぜ人間の頭につむじがあるのかという問題に帰着します(ほんまかいな).

続き

球面にきれいな足し算の構造が入ったとします. ここで"きれいな"を定義はしませんが近い点の演算結果は近いところに写るというイメージです.

ある点Pでの接平面の基底ベクトルを考えます. 0に近い点εをとりP+εの接平面を考えるとPと少しだけずれて接ベクトルも少しずれてるはずです. 足し算により球面上の任意の点までずらすことで, 球面全体で少しずつずれたベクトルの流れのようなものができることになります.

ここで@nishioさんがリンクしていたHairy ballの定理を使います. 2次元球面上ではどう頑張ってもどこかにベクトルの流れが止まってしまう点が出てくるという主張です. 上で「つむじが必ずある」と言ったのはそのイメージです.

矛盾が出てしまいました. つまり球面に足し算の構造が入ったという仮定が間違っていたことになり, 証明が完了します. ま, あくまでイメージですが.

正確にはLie群(きれいな足し算のできる物体)は平行化可能(parallelizable=接ベクトル空間のなすあつまり(バンドル)が自明). しかしS2は平行化可能でないのでLie群にはならないと言います.

11月4日_

セキュリティ・ミニキャンプ in 横浜終了.

新しい暗号技術』というタイトルでしゃべりました.

高校生向けということでどうするかかなり悩んだのだけど, 自分が高校生のときに聞いたらおもしろくてある程度は理解できてなんとか雰囲気は伝わるだろうというところを目指してみました.

有限体→トーラス→ペアリングの流れは幾何学的な見方を中心に進めてみました. それなりにうまくできたんじゃないかなとは思ってますが, 高校生からの感想が欲しいところ.

もちろん, ご専門の方からすると「これを入れないとあかんだろ」とか「この表現はおかしいだろう」とかいろいろあるかと思いますが, ご指摘いただけるとありがたいです.

11月2日_

横浜サイエンスフロンティア高校で暗号の話をしてみる.

空き時間にウーパールーパーを見せてもらった.

Visual Studio Express 2012の再インストールをしようとしてリンク先がことごとく2013になってしまってて焦る. ようやく見つけたのでメモ. download.

11月1日_

週末はセキュリティミニキャンプ

ここ数日酷い鼻風邪でへたってたが資料の準備もしなくていけないので大変.


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