<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>melancholic afternoon</title>
<link>http://homepage1.nifty.com/herumi/diary/latest.html</link>
<description>With Wnz</description>
<language>ja</language>
<lastBuildDate>Wed, 18 Nov 2009 19:14:49 GMT</lastBuildDate>
<generator>tekito ver. 2.0</generator>
<item><title>11/18 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#18</link>
<pubDate>Wed, 18 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(6)<br>
小数部のテーブルを3bit分整数部にもっていくことでテーブルサイズを小さくするためにはもとの
<pre class="box">
 int n = (int)floor(x) - 1;
 float d = x - n;
</pre>
する直前でxの値を8倍すればよい. 対応するd0, d1のビットも相応にずらす.
expを求めるところは8分の1にする必要があるので
<pre class="box">
 e = exp(n - 1.0) * exp(d0 + 1) * exp(d1 - 1);
</pre>
から
<pre class="box">
 e = exp((n - 1.0) / 8) * exp((d0 + 1) / 8) * exp((d1 - 1) / 8);
</pre>
となる. 近似計算は上はexp(d1 - 1) = 1 + (d1 - 1) = d1とできていたが,
下はexp((d1 - 1) / 8) = 1 + (d1 - 1) / 8 = (d1 + 7) / 8となる.
この計算を更に簡略化してみよう. d1は1にすごく近い値, 厳密には
d1 = 1 + α/2<sup>24</sup>.
α &lt;= 2<sup>14</sup>である. 代入すると(d1 + 7) / 8 = 1 + α/2<sup>27</sup>.
つまりd1をつくるところで
<pre class="box">
  fi.i =0x3f800000 | α // 0x3f800000は1.0fのバイナリ表現
  d1 = fi.f;
</pre>
としていたところを
<pre class="box">
  fi.i =0x3f800000 | (α &gt;&gt; 3);
  d1 = fi.f;
</pre>
とすれば(d1 + 7) / 8を計算できる. FPUの足し算1回とFPUの掛け算1回が整数のbitシフト1回に減るわけだ.
トータルコストとしては最初の掛け算1回と今回のシフト1回のコストが増えるがテーブルサイズが半分になる(あと情報落ちに関する誤差が若干増える).
場合によってはこちらを採用してもよいだろう.
ちなみに
<pre class="box">
    for (float x = 0; x &lt;= 20; x+= 1e-5f) {
        sum += exp(x);
    }
</pre>
を計算してみると, 今までの高速化ではオリジナルexp()による演算結果と厳密一致(!)してたが, テーブルサイズ半分の場合は相対誤差4e-7ほど出た(まあ問題ないレベルだと思うが).<br>
xを0から2まで1e-6ずつ増やしながらexp()の和を計算するベンチマーク(詳細は<a href="../prog/src/exp.cpp">exp.cpp参照</a>).
テーブル半分じゃないバージョンも<a href="#12">前回</a>より多少ブラッシュアップした.

<table border=1 width="90%" summary="exp5-1">
<caption>Core2duo 2.6GHz</caption>
<tr><th> <th> 32ibt@VC10 <th> 64bit@VC10</tr>
<tr><th> org exp <th> 0.828 <th> 0.250</tr>
<tr><th> my exp  <th> 0.219 <th> 0.109</tr>
<tr><th> my exp(テーブル半分) <th> 0.359 <th> 0.156</tr>
</table>

<table border=1 width="90%" summary="exp5-2">
<caption>Opteron 2376 2.3GHz</caption>
<tr><th> <th> 32ibt@gcc 4.4.1 <th> 64bit@gcc 4.4.1</tr>
<tr><th> org exp <th> 1.22 <th> 4.65</tr>
<tr><th> my exp  <th> 0.50 <th> 0.43</tr>
<tr><th> my exp(テーブル半分) <th> 0.560 <th> 0.48</tr>
</table>
32bitVCだとオリジナルの3.5～4倍, 64bitVCで2～3倍, 32bit gccで2～2.5倍, 64bit gccで10倍(?)速い.
やっぱりgccのoriginal expは遅い. expを多用する数値計算してる人はgccをVCにするだけで幸せになれるかもしれない.
]]></description>
</item>
<item><title>11/17 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#17</link>
<pubDate>Tue, 17 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(5)<br>
少し間が空いてしまった.
<pre class="box">
// __m128 d;
float e;
*(int*)&amp;e = _mm_cvtsi128_si32(_mm_castps_si128(d));

&gt;最後の2行はx86ではfloatはFPUレジスタに入れて返すのでこうするしかない.
</pre>
と書いていたけどヘッダを見ていて_mm_cvtss_f32という関数があるのに気がついた.
これを使えば
<pre class="box">
float e = _mm_cvtss_f32(d);
</pre>
とかける. 32bit環境ではスタックを経由してFPUレジスタにコピーされる.
x64環境ではFPUがXMMレジスタを使うので何の命令も生成せずに(見かけ上)変換できる.
すばらしい.<br>
ところで下記バージョンではテーブルサイズが整数用に7bit, 小数用に12bit必要だった.
整数と小数は本来つながっているので3bit分の小数部分を整数に持っていけば
整数部7 + 3 = 10bit, 小数部12 - 3 = 9bitとなり, テーブルサイズが4224 dwordから1536 dwordと半分以下になる.
そのためにはxを最初に*8して補正すればよい. 詳細は次回.
]]></description>
</item>
<item><title>11/12 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#12</link>
<pubDate>Thu, 12 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(4)<br>
帰りの電車の中でexp()のC版をそのままSISD(not SIMD)を使って実装してみた(<a href="../prog/src/exp2.cpp">exp2.cpp</a>).
<table border=1 width="90%" summary="core2duo 1.8GHz">
<caption>core2duo 1.8GHz</caption>
<tr><th> <th> VC9(32bit) <th> VC10(32bit) <th> VC10(64bit) <th> gcc 4.3.4(32bit)</tr>
<tr><th> org exp <th> 1.625 <th> 1.563 <th> 0.516 <th> 2.72</tr>
<tr><th> my C exp <th> 1.484 <th> 1.031 <th> 0.500 <th> 0.75</tr>
<tr><th> my SISD exp <th> 0.734 <th> 0.359 <th> 0.250 <th> 0.20</tr>
</table>
なかなかいい感じ(gcc 4.1.2だとちゃんと動かなかった). VC9からVC10への最適化性能の向上も凄いものがあるな.
次はもうちょいテーブルサイズを小さくできないか考える.
SSE4ならもっと簡単にできるんだけどな. 一応コードの説明.
<pre class="box">
float Exp2(float x)
{
static const float one = 1.0f;
static const unsigned int mask2 = (mask(8) &lt;&lt; 23) | mask(11);

// float xの値をx1に代入
__m128 x1 = _mm_load_ss(&amp;x);
// floor(x1)を求めて1を引く
int n = _mm_cvttss_si32(x1) - 1;
</pre>
ここで負の無限大への切り捨てが使えれば負の場合を場合分けせずにできるはず.
それはSSE4のroundssだと可能だけど, SSSE3までだとSSEの浮動小数制御レジスタを触る必要がありコストが高い.
大量のfloat配列を一度にexpする場合はまだしも1回ごとに触るのは微妙.
しかたないのでとりあえず最初に場合分けしてる.
<pre class="box">
__m128 d = _mm_setzero_ps();
d = _mm_sub_ss(x1, _mm_cvtsi32_ss(d, n));
</pre>
整数にしたnを再度浮動小数に戻してx1から引く. _mm_setzero_ps()は無くてもよいが出力コードを見る限りあった方がよいコードが生成された.
依存関係を断ち切れるからかな.
<pre class="box">
__m128i di = _mm_castps_si128(d);
unsigned int d0i = (unsigned int)_mm_cvtsi128_si32(di) &gt;&gt; 11 &amp; mask(12);
</pre>
__m128と__m128iは異なる型なのでキャストが必要. _mm_castps_si128を使って行う.
これはあくまでCで必要なだけでSSEとして対応する命令があるわけではない.
<pre class="box">
d = _mm_and_ps(d, _mm_load_ss((float*)&amp;mask2));
d = _mm_mul_ss(d, _mm_load_ss(&amp;expTbl0[n + 1]));
d = _mm_mul_ss(d, _mm_load_ss(&amp;expTbl1[d0i]));
float e;
*(int*)&amp;e = _mm_cvtsi128_si32(_mm_castps_si128(d));
</pre>
テーブル引きして掛け算する. 最後の2行はx86ではfloatはFPUレジスタに入れて返すのでこうするしかない.
x64だとSSEレジスタをそのまま返せるので余計なキャストやメモリアクセスは不要.
]]></description>
</item>
<item><title>11/11 ・カップヌードルが98円...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#11</link>
<pubDate>Wed, 11 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
・カップヌードルが98円で安いと買って帰ってよくみたらスープヌードルだった. 二度目な気がする.<br>
・三井住友VISAカードのポイント交換ページの景品選択方法が酷い. たとえば2130ポイントあったら2000ポイント以上で絞り込みたいのが普通だと思うのに,
選択ダイアログは2001～3000というものしかない. 2000ポイント丁度の景品を見るためだけに1001～2000を選択しないといけない(しかもそれだと最後のページに置かれるので何度もクリックしないといけない).
設計した人絶対自分で試してないだろ. そもそもたいした景品数が無いのだから視認性のよい一覧ページを作ればよいのに. 昔はそうだった気がする.
]]></description>
</item>
<item><title>11/10 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#10</link>
<pubDate>Tue, 10 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(3)<br>
<ul>
	<li>
    下記の方法で分割したd3は仮数の上位16bitは0(下位7bitしか残ってない)なので非常に1に近い. d3 - 1 &lt; 2<sup>-16</sup>.
    これならx &lt;&lt; 1のときのe<sup>x</sup> = 1 + x + x<sup>2</sup>が使える. 今の場合x<sup>2</sup>は無視できるのでexp(d3 - 1) ～ 1 + (d3 - 1) = d3.
    <li>
    仮数部は23bitしかないのだから2<sup>-12</sup>より小さいと2乗の項を無視できる. 逆に言うとfは上位12bitしかいらない.
    そのぐらいなら1回でテーブル引きしてしまってもよいかもしれない.
    <li>
    ここまでの考察を実装して試してみる.
</ul>
負なら最後に逆数を計算するのでそのためのフラグを保持する.
<pre class="box">
float Exp(float x)
{
    bool isPositive;
    if (x &gt;= 0) {
        isPositive = true;
    } else {
        x = -x;
        isPositive = true;
    }
</pre>
x を 整数部 n と d ∈ [1, 2) に分ける．
<pre class="box">
    int n = (int)floor(x) - 1;
    float d = x - n;
</pre>
浮動小数演のビットパターンを取り出す.
*(int*)&amp;dとかするとstrict-aliasing ruleを破るのでunionを使う.
<pre class="box">
    union fi {
        float f;
        unsigned int i;
    };
    fi fi;
    fi.f = d;
    unsigned int di = fi.i; // これで di は d のビットパターンになる
</pre>
dを二つの小数d0, d1に分ける. それぞれの仮数は12bitと11bitで論理和を取るとdの仮数となるようにする.
mask(n)はn bitのマスクを作る関数. d0は上位12bit部分.
<pre class="box">
    fi.i = di &amp; ((mask(8) &lt;&lt; 23) | (mask(12) &lt;&lt; 11));
    float d0 = fi.f;
</pre>
d1は下位11bit分.
<pre class="box">
    fi.i = di &amp; ((mask(8) &lt;&lt; 23) | mask(11));
    float d1 = fi.f;
</pre>
ここまででx = n + d0 + d1 - 1となってる(下の(***)の説明の部分相当).
よって
<pre class="box">
    float e = exp(n) * exp(d0) * exp(d1) / exp(1.0);
</pre>
で計算可能となった(この式変形は情報落ちを除いて厳密). 最後にもともと負だったら逆数を求める.
<pre class="box">
    if (!isPositive) {
        e = 1 / e;
    }
    return e;
}
</pre>
さて高速化. d1 - 1が0に近いことを利用としてexp(d1 - 1) = 1 + (d1 - 1) = d1とする.
nとd0に関するexpはそれぞれ7bit, 12bitのテーブルを用意する.

<pre class="box">
static float expTbl0[128 + 1];
const size_t d0MaskLen = 12;
static float expTbl1[1 &lt;&lt; d0MaskLen];
#define NUM_OF_ARRAY(x) (sizeof(x) / sizeof(*x))
void InitExp()
{
    for (int i = 0; i &lt; NUM_OF_ARRAY(expTbl0); i++) {
        expTbl0[i] = exp((float)i - 1);
    }
    for (int i = 0; i &lt; (1U &lt;&lt; d0MaskLen); i++) {
        fi fi;
        fi.i = (127 &lt;&lt; 23) | (i &lt;&lt; 11);
        expTbl1[i] = exp(fi.f);
    }
}
</pre>
d0に関するテーブル引きのための指数(d0i)取り出しはもともとのdiを使えばよい.
<pre class="box">
    int d0i = (di &gt;&gt; 11) &amp; mask(12);
</pre>
これで
<pre class="box">
    float e = expTbl0[n + 1] * expTbl1[d0i] * d1;
</pre>
という計算に置き換えられた. 実際に試してみる. 0～2までのxに関して最大誤差と平均誤差と処理時間@CoreDuo 1.66GHz(<a href="../prog/src/exp.cpp">exp.cpp</a>).
<pre class="box">
// VC9(32bit)
max=4.768372e-007, ave=8.847215e-008
sum=19910788.588494, org exp time=2.000000
sum=19910788.038545, my  exp time=1.453000
</pre>
<pre class="box">
// gcc 4.3.4(32bit)
max=4.768372e-07, ave=9.258090e-08
sum=19910788.588641, org exp time=3.150000
sum=19910788.034149, my  exp time=1.490000
</pre>
おお, この時点で速くなってる(logもそうだがVCの超越関数速いなー).
floor()使うなら負数の場合もまとめて(整数部のテーブルを1bit増やして)テーブル引きしたほうがいいかもしれんな.
あと, 下に凸なexpを下から追いかけるのでどうしても値が小さい方にいってしまう. 何かうまい方法ないかなあ.
]]></description>
</item>
<item><title>11/9 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#9</link>
<pubDate>Mon, 9 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(2)<br>
<ul>
	<li>
    xをどううまく分割するかという話になった. 整数部を除くと精度は23bitなので8bit x 3のテーブルで処理できそうと考える.
    x = n(整数) + (2進数8桁) + (2進数8桁) + (2進数7桁).
	<li>
	ただ小数部を0～1の範囲にすると指数部も変わるためテーブル引きできない.
	<li>
	指数部を固定し, 仮数部のみの処理にしたいので小数部の正規化を考える. そのために0～1の範囲ではなく1～2の範囲にしよう.
	つまり x = n + d(n∈Z, d∈[1, 2)) とする.
	<li>そうすると, dを複数の小数の和に分解することが, 仮数部を適当な固定幅で切った論理和に置き換えられる.
</ul>
最後の部分を図で説明してみる. dが1以上2未満のとき, d = sign ・ 2<sup>指数</sup> ・ (1 + 仮数 / 2<sup>24</sup>)
と表すとsign = 0, 指数 = 0と固定され, 動くのは仮数fのみとなる.
よって, たとえばfを8bit, 8bit, 7bitの論理和に分けてみると
<pre class="box">
f = f1 | f2 | f3
f1 = f &amp; 0b11111111000000000000000
f2 = f &amp; 0b00000000111111110000000
f3 = f &amp; 0b00000000000000011111111
</pre>
d = (1 + f / 2<sup>24</sup>) = (1 + f1 / 2<sup>24</sup>) + (1 + f2 / 2<sup>24</sup>) + (1 + f3 / 2<sup>24</sup>) - 2
とできる. f1, f2, f3に相当する浮動小数をd1, d2, d3とすると, x = n + d1 + d2 + d3 - 2.(***)
よってe<sup>x</sup> = e<sup>n</sup> e<sup>d1</sup> e<sup>d2</sup> e<sup>d3</sup> / e<sup>2</sup>. だいぶいい感じ. 次にどういうビット幅をとればよいかを考える.
]]></description>
</item>
<item><title>11/8 float xに関するexp(x)の実...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#8</link>
<pubDate>Sun, 8 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
float xに関するexp(x)の実装を考える(1)<br>
<ul>
	<li>
    e<sup>-x</sup> = 1 / e<sup>x</sup>だからx &gt;= 0とする.
	<li>
    e<sup>x</sup> = Σx<sup>i</sup> / i!を使うのだけど収束に時間がかかるのでx = n + d(n∈Z, d∈[0, 1))と分解しよう.
    e<sup>x</sup> = e<sup>n</sup> e<sup>d</sup>. n～128程度でfloatの最大値になるからそちらはテーブル引きすればいい.
    <li>
    その場合11!=39916800～4.0e7だから1e-7の精度を出すにはΣはi = 11ぐらいまでとる必要がある.
    これは大きすぎる. d &gt;= 0.5の場合はd = 0.5 + d1, d1∈[0, 0.5)と更に分解してみよう.
    e<sup>x</sup> = e<sup>n</sup> e<sup>0.5</sup> e<sup>d1</sup>
    <li>
    この場合0.5<sup>8</sup>/8!～1e-6ぐらい. うーん, まだ大きい.d1 = 0.25 + d2, d2∈[0, 0.25)ともう一つ分けるか.
    それでも0.25<sup>6</sup>/6!～3e-7. いまいち. 別の方法を考える.
    <li>
    d1, d2は要は2進分数なんだからそちらもテーブル引きすればよさそう.
    <li>
    x = n + (2進数8桁のd1) + (次の2進数8桁のd2) + ...として全部テーブル引きでいいか.
    なら級数展開は不要だなあ.
</ul>
]]></description>
</item>
<item><title>11/7 昔作ってたlogの計算を...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#7</link>
<pubDate>Sat, 7 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
昔作ってた<a href="../adv/adv43.html#014">logの計算</a>をintrinsicでやってみた(<a href="../prog/src/log.cpp">log.cpp</a>).
とりあえずasmを焼き直しただけなので改良の余地は多々あるだろうがCore2Duo 1.8GHzでベンチ.
<table border=1 width="90%" summary="log bench">
<tr> <th> <th> 32bit VC9 <th> 32bit VC9 /fp:fast <th> 64bit VC <th> 32bit gcc 4.1.2 <th> 64bit gcc 4.1.2</tr>
<tr> <th> log <th> 0.687 <th> 0.375 <th> 0.188 <th> 0.48 <th> 0.330</tr>
<tr> <th> my_log <th> 0.156 <th> 0.125 <th> 0.130 <th> 0.110 <th> 0.100</tr>
</table>
計測がいいかげんなので有効数字2桁なさそうやけど32bitで概ね3～4倍. 64bitのVCのlogはがんばってるなあ.
昔はdivpsよりもrcpps+ニュートン補完が速かったんやけど今は違うのか?(要検証)
まあ, 昔の最適化が現在でもそれなりに意味はあると分かったので次はexpを考えたい.
]]></description>
</item>
<item><title>11/6 from_time_tの問題は1.41.0で...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#6</link>
<pubDate>Fri, 6 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
from_time_tの問題は1.41.0で<a href="http://beta.boost.org/users/news/version_1_41_0">対応する</a>っぽい. と思ったらまだ駄目だった.
]]></description>
</item>
<item><title>11/5 ・第二回カーネル/VM探...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#5</link>
<pubDate>Thu, 5 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
・<a href="http://atnd.org/events/1663">第二回カーネル/VM探検隊</a><br>
ほどほどに面白かった. ただ16時～20時半の長丁場は辛かった. 途中でおなか空きすぎて頭が半分回ってなかった.
MINIX SMPのところで66h, 67hをnopに置き換えてる理由がわからないと言ってはったので32bitモードで16bitコード生成したいからとちゃうって適当に答えてしまったが,
ソースのコメントに<a href="http://d.hatena.ne.jp/masami256/20090926">書いてあった</a>.<br>
・副都心線初めて乗った. 渋谷で上に出ようとして階段使ったら100段あった. なんて深いところにあるんや.
]]></description>
</item>
<item><title>11/4 ・CANS2009で発表するF212...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#4</link>
<pubDate>Wed, 4 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
・CANS2009で発表するF<sub>2</sub><sup>1223</sup>, F<sub>3</sub><sup>509</sup>上のTateペアリングのソースコードが<a href="http://delta.cs.cinvestav.mx/~francisco/temp/Page-TatePairing2009/TatePairing-2009.html">公開された</a>.
私は途中参加だったのでC++ならもちっと楽できるんだけどなあと思いつつ郷に従う. なにはともあれ, こういう最速狙うコードで公開されてるのは殆ど無いのでめでたい.<br>
・下記のposix_time::from_time_tの件, <a href="http://archives.free.net.ph/message/20070215.160245.d6f19054.de.html">2007年に既に指摘されてる</a>のに直ってないということは直す気ないんやろか. trackが見えんでよう分からん.
こっちの人もfrom_time_tについて<a href="http://lists.boost.org/boost-users/2007/07/29567.php">何か言ってる</a>なあ. これも2年前だ.
]]></description>
</item>
<item><title>11/2 boost::posix_time::from_time_t...</title>
<link>http://homepage1.nifty.com/herumi/diary/0911.html#2</link>
<pubDate>Mon, 2 Nov 2009 14:59:59 GMT</pubDate>
<description><![CDATA[
boost::posix_time::from_time_t(time_t)は64bit用time_tに対応してないぽい(boost 1.40).
VC9@32bit, gcc 4.1@64bitで確認.
<pre class="box">
#include &lt;stdio.h&gt;
#include &lt;time.h&gt;
#include &lt;iostream&gt;
#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;
#include &lt;boost/date_time/gregorian/gregorian.hpp&gt;

void Put(time_t t)
{
    struct tm tm;
    char buf[64];
#ifdef _WIN32
    _gmtime64_s(&amp;tm, &amp;t);
    asctime_s(buf, &amp;tm);
#else
    gmtime_r(&amp;t, &amp;tm);
    asctime_r(&amp;tm, buf);
#endif
    printf("time=&#37;s", buf);
}

int main()
{
    time_t t;
    boost::posix_time::ptime bt;

    time(&amp;t);
    printf("sizeof=&#37;d\n", sizeof(t));
    Put(t);
    bt = boost::posix_time::from_time_t(t);
    std::cout &lt;&lt; "boost:" &lt;&lt; bt &lt;&lt; std::endl;

    std::cout &lt;&lt; "boost:" &lt;&lt; (bt + boost::gregorian::years(29)) &lt;&lt; std::endl;

    t += 84600 * 365 * 29;

    Put(t);
    bt = boost::posix_time::from_time_t(t);
    std::cout &lt;&lt; "boost:" &lt;&lt; bt &lt;&lt; std::endl;

}

sizeof=8
time=Mon Nov 02 13:39:33 2009
boost:2009-Nov-02 13:39:33
boost:2038-Nov-02 13:39:33
time=Sat Mar 20 01:09:33 2038
boost:1902-Feb-11 18:41:17 ; おかしい
</pre>
sizeof(time_t) = 4な環境で駄目なのはしかたないけど, そうじゃない環境では対応しておいて欲しいなあ.
言ってみるか.
<pre class="box">
  ptime from_time_t(std::time_t t)
  {
    ptime start(gregorian::date(1970,1,1));
    return start + seconds(static_cast&lt;long&gt;(t));
  }
</pre>
longにキャストしてるからか? でも64-bit Linuxでも駄目なんだよなあ.
]]></description>
</item>
</channel></rss>
