円周率の計算 (3)
前回までの記事で書き忘れていたことがあったので、補足しておきます。
まず、「pi_atan.pde」の中の
#define ADDSUBONLY 1
の行を削除あるいはコメント・アウトして、「ADDSUBONLY」というシンボルが未定義な状態にすると、MUL / ROL 命令を使ったプログラムになり、実行時間が短縮されます。
ただし、AVR の場合は左ローテイト命令は存在せず、ニモニックは「ROL Rd」でも、実際には「ADC Rd,Rd」命令にアセンブルされます。
したがって、左ローテイト命令を使った (つもりの) 除算ルーチンでも、実は加算命令しか使っていないことになります。
RETROF-8 の場合には左右シフト / 左右ローテイト命令は存在せず、さらに ADC 命令も存在しないので、1命令では実現できませんが、複数命令を費やせば同等の動作をさせることは可能です。
各公式ごとの実行結果の表に、多倍長配列の要素数 (バイト単位) の欄を追加しました。
計算には、この長さの多倍長配列を 3 本使っています。
公式 | 有効桁数 | 実行時間 (s) (加減算のみ) |
実行時間 (s) (シフトあり) |
多倍長配列 (バイト) |
---|---|---|---|---|
Machin | 180 | 1.5 | 0.3 | 77 |
Gauss | 322 | 5.0 | 0.9 | 137 |
Stoermer | 451 | 10.9 | 1.8 | 191 |
atan255 | 608 | 29.8 | 4.8 | 255 |
実際には、最大長である 255 バイトの配列をグローバル変数として宣言して、コンパイル時にスタティックに割り付けておいて、実行時には、各公式で必要な分だけを計算に使っています。
ここで、正しく動作するのは ATmega328P を使っているタイプの Arduino だけで、ATmega168 を使用しているタイプでは、コンパイル時にエラーにはなりませんが、実際には実行時に RAM が不足して正しく実行できず、出力が出ません。
ファイル「pi_atan.h」の中の
#define MP8LEN_MAX LEN_atan255
の行の「LEN_atan255」を「LEN_Stoermer」に書き換え、「pi_atan.pde」の setup() 関数の中の atan255() 関数呼び出しを削除して、Störmer 公式の出力までに限れば実行できます。