![日記 日記](https://srad.jp/static/topics/journal_64.png)
yasuokaの日記: Z80における「手抜き」回転行列の改良 9
日記 by
yasuoka
一昨日・昨日の日記を読み返していて、これ、今の私(安岡孝一)だったら、sinθ≒1/8じゃなくて、sinθ≒511/4096にしちゃうんだろうな、と思えてきた。その方がcosθ=127/128に近いからだ。
┌ cosθ -sinθ ┐ ┌ x ┐
└ sinθ cosθ ┘ └ y ┘
ただ、sinθ≒1/8に比べると、sinθ≒511/4096はインパクトが弱いし、何よりプログラムが長くなる。HLレジスタのHレジスタに符号付整数、Lレジスタに256を分母とする分数が入っているとすると、511/4096の乗算は
7C LD A,H
2F CPL
5F LD E,A
CB 2B SRA E
07 RLCA
9F SBC A,A
57 LD D,A
19 ADD HL,DE
7D LD A,L
CB 2C SRA H
1F RRA
CB 2C SRA H
1F RRA
CB 2C SRA H
1F RRA
6F LD L,A
となってしまって、かなり長いし読みにくい。うーん、もうちょっと何とかならないかな…。
sinθ=1/16とすると (スコア:1)
sinθ=1/x のとき cosθ≒1-1/(2x2) [srad.jp]
から、
cosθ≒511/512
sinθ=1/16
はどうでしょう?
Re:sinθ=1/16とすると (スコア:2)
k=9の場合 [srad.jp]ですね。これ、4ビットシフトを無理矢理
でやってみようとしたり、結構たのしく考えたんですけど、ちょっと回転量が小さすぎて、結局k=7の方を採用した覚えがあるのです。
Re:sinθ=1/16とすると (スコア:1)
> ちょっと回転量が小さすぎて、
ああ、これは重要ですね。
今どきなら微小な回転を高速にやって「ぬるぬる」動かすところでしょうけど
sinθ=1/128 はどうでしょうか? (スコア:1)
Kitawaki
Re:sinθ=1/128 はどうでしょうか? (スコア:2)
えっと、イマイチ良くわからないのですけど、32767/32768って、16ビットじゃほとんど計算できない気がするのです。すみません、整数部と分数部に何ビットずつ使う実装を想定してるんでしょうか?
結果保持の桁数 (スコア:1)
ここまでいくと、計算結果の精度(固定小数点で、小数点以下8bit)が足りなくなるんじゃないですかね。
昔(といっても、MS-DOS、V30、コプロなしぐらいのころ)いろいろ遊んで思い出としては、
回転行列が小数点以下8bitだと、ぐるぐる回してると目に見えて誤差がたまってきます。
で、積算する回転行列は整数部6bit小数部10bitにして、最後に一回だけ移動も含めた座標計算を行う、という形に落ち着きました。
#当初は特に最終目的もなく回転させたくて回転させてたんですが、最終的に出来たのはHOSの起動画面。記憶に頼ったコピーなので、本物とはだいぶかけ離れてましたが、リアルタイムにグルグル回すのはそれなりに楽しかった。
Z80における「手抜き」回転行列の改良の計算誤差 (スコア:2)
以下のプログラムを作ってみて、IX=6400H,IY=0000Hから回したところ、434回よびだしたところでIX=BF73H,IY=B251Hとなって、誤差が1%を超えました。sinθ≒1/8が190回 [srad.jp]だったので、まあまあ良くなってるんですけど、分数部8ビットだと「もう一声」かなぁ…。
回転行列と三角行列 (スコア:1)
Z80の最盛期に微妙に間に合わなかった手法として、
回転行列を上三角行列と下三角行列の積に分解するやり方があります。
R=UDU (三角行列の非対角成分はu_12=-tan(θ/2), d_21=sinθ)
Wikipediaの記事 [wikipedia.org]によれば1986年に論文で発表されたものらしいので、
実際には使われた例は無さそうですが。
これの良い所は係数の精度が悪くてもdet(R)=1が保証される点や、
可逆的に逆回転を行える点。
動径方向の累積誤差は殆ど無いとみられます。
恐らくsinθ≒1/8, tan(θ/2)≒1/16なんて粗い値を使っても、
遠目にはなんちゃって円運動に見えてくれるのではないでしょうか。
Paethの回転アルゴリズム (スコア:2)
このアルゴリズム、かなりの優れモノのようです。私(安岡孝一)の今日の日記 [srad.jp]にちょっとだけ書いてみたので、よければどうぞ。