2012年11月11日(日) [長年日記]
■ [c][dev] x86での浮動小数点演算
x86上のGCCでコンパイルしたプログラムの動作が、x64上のそれと異なっていた。調べると、両者の浮動小数点演算のデフォルトの振る舞いが違うみたい。gccのmanに次のようにある。
-mfpmath=unit 選択されたユニット unit のための浮動小数点演算を生成します。unit た めの選択は次の通りです: 387 チップの大多数に存在する標準の 387 浮動小数点コプロセッサを使用 し、そのほかは、エミュレートされます。このオプションつきでコン パイルされたコードは、ほとんどすべての点で動作します。一時的な 結果は、他のチップの大部分と比べて、わずかに異なった結果をもた らすタイプによって指定された精度の代わりに 80 ビットの精度で計 算されます。より詳細な記述については -ffloat-store を参照してく ださい。 これは i386 コンパイラのためのデフォルトの選択です。 sse SSE 命令セットに存在するスカラ浮動小数点命令を使用します。この 命令セットは Pentium3 以降、Athlon-4, Athlon-xp と Athlon-mp チップによる AMD 系列でサポートされます。SSE 命令セットの初期の バージョンは、単精度演算のみをサポートし、そのため、倍精度と拡 張精度演算は、まだ 387 を使用して行われます。後のバージョン、 Pentium4 でのみ存在し、将来の AMD x86-64 チップは、倍精度演算も サポートしています。 i386 コンパイラに関して、利用者は、SSE 拡張を有効にして、このオ プションが効果があるようにするために、-march=cpu-type, -msse ま たは -msse2 スイッチを使用する必要があります。x86-64 コンパイラ について、これらの拡張はデフォルトで有効にされています。 結果のコードは、大多数の場合にかなり速くなり、387 コードの数値 不安定性問題を避けるべきですが、一時的なものを 80 ビットと期待 するいくつかの既存のコードを壊すかもしれません。 これは x86-64 コンパイラのためのデフォルトの選択です。
なので、x86上だとデフォルトで「80 ビットの精度で計算」され、x64上だと80ビットでは計算されないようだ。80ビットでの計算のついてはBinary HacksのHACK#98「x86が持つ浮動小数点演算命令の特殊性」でも触れられていた。
上の引用を参考に、x86上でのコンパイル時に「-mfpmath=sse -msse2」というオプションを付けるようにしたらx64と同じ振る舞いになるようになった。以下サンプルコード。
同一引数の関数呼び出し結果が不一致
次のプログラムをx86上のGCC 4.6.3でオプションなしでコンパイルすると、「not equal」が出力される。えー。
「-mfpmath=sse -msse2」オプションを付ければめでたく「equal」と出力され、これはx64上での動作と一致する。
#include <stdio.h> double f(double d) { return d + 1.0; } int main() { if (f(0.1) == f(0.1)) { printf("equal\n"); } else { printf("not equal\n"); } return 0; }
doubleからintへのキャスト
次のプログラムをx86上のGCC 4.6.3でオプションなしでコンパイルすると
0 1 2 2 4 5 5 6 8 9
と出力され残念な感じ。「-mfpmath=sse -msse2」オプションを付けると
0 1 2 3 4 5 6 7 8 9
と出力される。
#include <stdio.h> int main() { int i; for (i = 0; i < 10; ++i) { double d = i / 10.0; int j = d * 10.0; printf("%i ", j); } printf("\n"); return 0; }
2012年11月13日(火) [長年日記]
■ [c++] boost::bindは演算子と組み合わせられる
std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind( &X::name, _1 ) == "Paul" );
みたいに書けると知らなかったのでメモ。上の例はboostのドキュメントにあったもの。
For convenience, the function objects produced by bind overload the logical not operator ! and the relational and logical operators ==, !=, <, <=, >, >=, &&, ||.
とのこと。サンプルコードをメモ。
#include <algorithm> #include <iostream> #include <vector> #include <boost/bind.hpp> class A { int a; public: A(int a) : a(a) {} int get() const { return a; } }; int main() { std::vector<A> v; v.push_back(A(1)); v.push_back(A(2)); v.push_back(A(3)); std::vector<A>::iterator it = std::find_if(v.begin(), v.end(), boost::bind(&A::get, _1) == 2); if (it == v.end()) { std::cout << "not found" << std::endl; } else { std::cout << it->get() << std::endl; } }
これで「2」と出力される。
C++11のbindでもできるのかは知らない。
2012年11月14日(水) [長年日記]
■ [life] 免許証を更新した
受付で旧免許証とお知らせハガキを渡すと用紙を貰えた。用紙に名前電話番号生年月日などを記入しハガキと共に3番窓口へ提出。すると3100円払えとのこと。前回より300円高い。
用紙とハガキは返却され領収書を貰い4番窓口へ行くと視力検査。箱の中を覗くタイプ。見えた、合格、よかった。
次は5番でタッチパネルに暗証番号を入力せよとのこと。事前にメモしておいた番号を入力すると、その番号が大きく印刷された紙が出てきてそれを貰えた。メモしておかなくても大丈夫だったみたい。
6番で用紙と旧免許証を提出。ここで用紙に新免許証の情報が印刷されたように思う。旧免許証は穴を開けられたが返してもらえた。
7番で再び用紙を提出。ここでは何をしたのだったかなあ。本籍に間違いがないか確認をしたか。8番で椅子に座って写真撮影。よくわからないうちに撮り終わっていた。えー。
これで残すは講習のみ。平日だからかすいていて、ここまでスムーズにこれた。用紙の重要部分は切り取られ、手元にあるのは半券状態の部分だけ。これを講習の受付に見せると、次の講習開始は40分後とのこと。存外に待たされる羽目に。
待つこと40分で講習開始。椅子が並べられた狭い部屋で講師の話を聞く。道路交通法の改正点の説明など。時速80kmで走っている車が急ブレーキを踏んで止まるまでに76m進むとのこと。後部座席もシートベルト着用義務あり。聴覚障害者マークというのができたのか。右折の矢印信号でUターンしてもいいことになった。講師の説明は20分以上続いた。以前はビデオを見るだけだったけどなあ。都道府県による違いか。
残りの時間でビデオを見たけどビデオの途中で規定時間になり終了。そしてその場で半券と交換で新免許証を貰える。これも以前とは違う。新免許証に対し先程決めた暗証番号の確認をしておしまい。写真は変な顔だった。