アセンブラで円周率を求める
2007年4月30日
16ビット長の変数で円周率が 3.1416 まで求められることが分かったので、アセンブラで計算してみた。インテル 80386 系は、レジスタが32ビット。16ビットどうしの乗算を行っても、結果が32ビット内に収まるので、比較的容易にアセンブラで書ける。
このコードで、3.1416 をはじきだすことが出来る。
ここでは、乗算命令に mul を用いているが、これを加算命令のみで実行できるように改変する必要がある。
最後に除算で円周率を求める部分は、比較的容易なコードで実現できることが分かった。
上記のコードから、アセンブラの『mul』命令を除いてしまうと、次のようなコードになった。
ここまでのシミュレーションで分かったことは、以下のとおり。
1)フラグは、ゼロフラグとキャリーフラグの二つでよい。
2)初期の段階でスタックを実装することが、望ましい。
レジスタの数を減らして、メモリとのアクセスを充実させるような設計(モトローラ型)の方が、CPUの設計としてはやりやすいかもしれない。当初の計画では、メモリを使う頻度を減らすインテル型のCPUにする予定であった(メモリをフリップフロップで作成するのに骨が折れるため)が、このあたりの仕様について再考すべし。
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
double sub(int step);
int main (){
unsigned int step=65536;
for(unsigned int i=0;i<(0x1fffffff-step);i+=step){
double pai=sub((int)step);
printf( "%d %f\n", i, pai);
if (kbhit()) return 0;
}
while (!kbhit());
return 0;
}
double sub(int step){
int i;
double pai;
static unsigned int num,inside;
unsigned int r1,r2;
_asm mov ecx,step;
label05:
//get 16 bit random values (note that max value of rand() is 32767)
_asm push ecx;
r1=(rand() & 0x7fff)*2 + (rand() & 1);
r2=(rand() & 0x7fff)*2 + (rand() & 1);
_asm pop ecx;
//Determine if inside circle
_asm mov eax,r1;
_asm mul eax;
_asm mov ebx,eax;
_asm mov eax,r2;
_asm mul eax;
_asm add eax,ebx;
_asm jc label10;
_asm mov eax,inside;
_asm inc eax;
_asm mov inside,eax;
label10:
_asm mov eax,num;
_asm inc eax;
_asm mov num,eax;
_asm loop label05;
// Calculate the pai
//pai=4*(double)inside/(double)num;
unsigned int res=0;
_asm mov eax,inside;
_asm shl eax,2;
_asm mov edx,num;
_asm mov ebx,res;
_asm mov ecx,6;
label20:
_asm cmp eax,edx;
_asm jb label30;
_asm sub eax,edx;
_asm inc ebx;
_asm jmp label20;
label30:
_asm push edx;
_asm mov edx,0ah;
_asm mul edx;
_asm pop edx;
_asm shl ebx,4;
_asm loop label20;
_asm mov res,ebx;
// Determine pai from the res
pai=0;
for (i=0;i<6;i++){
res=res/16;
pai=pai/10+(double)(res%16);
}
return pai;
}このコードで、3.1416 をはじきだすことが出来る。
ここでは、乗算命令に mul を用いているが、これを加算命令のみで実行できるように改変する必要がある。
最後に除算で円周率を求める部分は、比較的容易なコードで実現できることが分かった。
上記のコードから、アセンブラの『mul』命令を除いてしまうと、次のようなコードになった。
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
double sub(int step);
int main (){
unsigned int step=65536;
for(unsigned int i=0;i<(0x1fffffff-step);i+=step){
double pai=sub((int)step);
printf( "%d %f\n", i, pai);
if (kbhit()) return 0;
}
while (!kbhit());
return 0;
}
double sub(int step){
int i;
double pai;
static unsigned int num,inside;
_asm mov ecx,step;
label05:
//Determine if inside circle
_asm call label_rand;//_asm mov eax,rand();
//_asm mul eax;
_asm mov edx,eax;
_asm call label_mul; // _asm mul edx
_asm mov ebx,eax;
_asm call label_rand;//_asm mov eax,rand();
_asm mov edx,eax;
_asm call label_mul; // _asm mul edx
_asm add eax,ebx;
_asm jc label10;
_asm mov eax,inside;
_asm inc eax;
_asm mov inside,eax;
label10:
_asm mov eax,num;
_asm inc eax;
_asm mov num,eax;
_asm loop label05;
// Calculate the pai
//pai=4*(double)inside/(double)num;
unsigned int res=0;
_asm mov eax,inside;
_asm shl eax,2;
_asm mov edx,num;
_asm mov ebx,res;
_asm mov ecx,7;
label20:
_asm cmp eax,edx;
_asm jb label30;
_asm sub eax,edx;
_asm inc ebx;
_asm jmp label20;
label30:
// eax=eax*10
_asm push edx;
_asm shl eax,1;
_asm mov edx,eax;
_asm shl eax,2;
_asm add eax,edx;
_asm pop edx;
_asm shl ebx,4;
_asm loop label20;
_asm mov res,ebx;
// Determine pai from the res (ebx)
pai=0;
for (i=0;i<7;i++){
res=res/16;
pai=pai/10+(double)(res%16);
}
return pai;
/* rand() */
label_rand:
_asm push ebx;
_asm push ecx;
_asm push edx;
i=(rand() & 0x7fff)*2 + (rand() & 1);
_asm pop edx;
_asm pop ecx;
_asm pop ebx;
_asm mov eax,i;
_asm ret;
/* eax=eax*edx */
label_mul:
_asm push ebx;
_asm push ecx;
_asm mov ebx,eax;
_asm xor eax,eax;
_asm mov ecx,010h;
label_mul_1:
_asm shr ebx,1;
_asm jnc label_mul_2;
_asm add eax,edx;
label_mul_2:
_asm shl edx,1;
_asm loop label_mul_1;
_asm pop ecx;
_asm pop ebx;
_asm ret;
}ここまでのシミュレーションで分かったことは、以下のとおり。
1)フラグは、ゼロフラグとキャリーフラグの二つでよい。
2)初期の段階でスタックを実装することが、望ましい。
レジスタの数を減らして、メモリとのアクセスを充実させるような設計(モトローラ型)の方が、CPUの設計としてはやりやすいかもしれない。当初の計画では、メモリを使う頻度を減らすインテル型のCPUにする予定であった(メモリをフリップフロップで作成するのに骨が折れるため)が、このあたりの仕様について再考すべし。