処理系の独自拡張は出来るだけ使いたくないのだが、アセンブラで書く量を出来るだけ少なくしたいと思うと、使用もやむなしといったところ。
処理系の独自拡張は出来るだけ使いたくないのだが、アセンブラで書く量を出来るだけ少なくしたいと思うと、使用もやむなしといったところ。
うーん、暑いですね。
たった一ファイルなのに、こんなに速いマシンなのに、コンパイル時間かかりすぎ。テンプレートとマクロで各モードの全組み合わせを生成しているせいだと思う。
と、.objファイルのサイズを見たら……100MB!!? あ、ありえねぇ……。
いろいろ調べてみたら、関数テンプレート内で、std::vector<関数ローカルクラス>を使っていたのが悪かったみたい。そりゃ、一つ一つのテンプレートインスタンスに対して個別のvectorができあがっちゃうわけで、肥大するわな。ローカルクラスを外に出したら10MBまで下がり、さらにvectorをやめて固定長の配列にしたら8MBまで下がった。
(n=0)かつ(sx + n * m00 - half < left)かつ(m00 > 0)という状況があったとして(すべて整数)、nが一つずつ増えていったときに、いくつになったときに初めて(sx + n * m00 - half >= left)になるかを考える。
sx + n * m00 - half >= left
両辺から同じ値を引いても不等号は変わらないので、
n * m00 >= left - (sx - half)
両辺を正の整数m00で割っても不等号は変わらないので、
n >= (left - (sx - half)) / m00 + (切り下げ誤差)
ただし、/は正の数同士の切り下げ除算である。/の左右は前提条件より正の数である。切り下げ誤差は1未満の小数で0から(m00-1)÷m00の範囲内である。
nが整数の中でいくつ以上なら不等式が成り立つかという話だったので、右辺を切り上げればよく、
n >= (left - (sx - half) + m00-1) / m00
となる。
今度は(n=0)かつ(sx + n * m00 - half > right)かつ(m00 < 0)という状況があったとして(すべて整数)、nが一つずつ減っていったときに、いくつになったときに初めて(sx + n * m00 - half <= right - one)になるかを考える。
sx + n * m00 - half <= right - one
両辺から同じ値を引いても不等号は変わらないので、
n * m00 <= right - one - (sx - half)
m00は負なので、そのままでは割れない。負数が入る除算は処理系定義なので注意。
両辺に-1をかけると左右の大小関係が逆になる。ただし、同じ値だった場合は符号を反転させても同じまま。
n * -m00 >= -(right - one - (sx - half))
両辺を正の整数-m00で割っても不等号は変わらないので、
n >= -(right - one - (sx - half)) / -m00 + (切り下げ誤差)
後は先ほどと同様に切り上げに直して、
n >= (-(right - one - (sx - half)) + -m00-1) / -m00
となる。
これでもいろいろと省略している。勝手に項を移動していたり、加減算や乗算の説明をしていないし、値の範囲を気にしていなかったり、切り上げとか切り下げとか説明していないし。
整数(固定小数点数)の場合はまだ予測しやすい。浮動小数点数なんて扱った日にはいろんなところで誤差が出るので、もうわけわかんね。
いけね、一番きついループの中で仮想関数を呼んでた。あまりに自然で非仮想だと思いこんでた。とりあえずこれで二倍くらいにはなる。あとは範囲チェックを外に追い出したいんだけど、こういうのは証明が苦手だと大変なんだよなぁ。ただこれが外に出せれば1.25倍くらいまでは縮まるはず。
現行の回転より三倍遅い。さて、どこまで縮められるか。
再放送をやってるので見た。懐かしすぎるね。エンディングへの入り方が当時とても印象的だったのを覚えている。