nshdot:lab /

IchigoJamでマンデルブロ集合

IchigoJamは浮動小数点演算ができない?

それなら固定小数点を使えばいいじゃない。

固定小数点

IchigoJamの変数は16ビットで-32768~32767の整数を表せる。 この16ビットの途中のどこかに小数点があるものと考える、というのが固定小数点の考え方。どこに少数点を置くかは、必要な値の範囲と精度に応じて決める。 例えば、4ビット目と5ビット目の間に小数点があるものと考えると、上位4ビットが整数部、残りの12ビットが小数部なので、-8.000~7.999ぐらいの範囲の数を表せることになる。この型式を指して「4.12」とか言ったりする。

固定小数点の足し算や引き算は整数型と全く同じなので特にどうということもない。でも掛け算とかでは、小数点が移動することを考慮して補正する必要がある。 たとえば例のような固定小数点表現を普通の整数型として見ると、本来の値を左に12ビットシフトしたものになっているので、そのまま2つの値を掛け算すると、元の値を左に12x2=24ビットシフトした値になってしまう。

そこで、まず掛け算をする前に、それぞれの値を右に6ビット分だけ算術シフトしておく。 (今のIchigoJamの>>は論理シフトになるので、代わりに26=64で割り算すればいい。) そうすると、それらを掛けた結果はちょうど元通りのシフト量になる。 もちろん、掛け算の結果が範囲を超えた値になったらオーバーフローするし、最初に右シフトした段階で下位のビットが失われるのでアンダーフローもする。 でも、あらかじめシフトしておく量は合計12ビットならどういう組み合わせでもいいので、もしも値の範囲があらかじめ分かっているなら、大きい方の値を多めにシフトするとかしたら、アンダーフローは若干改善される。

マンデルブロ集合

というわけで、4.12の固定小数点で演算してマンデルブロ集合を描画してみる。 セミグラフィックの粗い解像度なら、演算の精度はあんまり問題にならないはず。

ソース

1 'Mandelbrot set 10 N=32 11 W=64:H=48 12 A=2<<6:B=A*A:C=(3<<12)/W 20 CLS 21 forY=0toH-1:V=(Y-H/2)*C 22 forX=0toW-1:U=(X-(W*3)/4)*C 25 Z=#900+(X/2)+(Y/2)*32 26 J=1<<((Y%2)*2+(X%2)) 27 K=J|#80|PEEK(Z) 28 POKE Z,K 29 P=U:Q=V:I=0 30 R=P/64:P=R*R:if P<0 GOTO40 31 S=Q/64:Q=S*S:if Q<0 GOTO40 33 if P+Q<0 or P+Q>B GOTO40 34 P=P-Q+U 35 Q=2*R*S+V 36 I=I+1:if I<N GOTO30 37 POKE Z,(K^J) 40 next 41 next 99 END

使い方

RUNするだけ。 (全部描画するのに15分9分ぐらい。)

(2017/01/14追記) ちなみにLPC1114が本気出したら数十ミリ秒とかそんなレベルになるらしい。

実行例