MIPSアセンブリを使用して整数の平方根を正確に見つけるにはどうすればよいですか?
7 に答える
この質問に提出されたようなアルゴリズムを使用して、必要に応じて適応させることができます。MIPS に入る前に、C での実装を見てみましょう。
//Function to compute sqroot(n)
int sqroot(int n) {
int x = n;
for (int i = 0; i < (n/2); i++)
x = (x + n / x) / 2;
return x;
}
このsqroot(n)
関数は、 の平方根の床に相当する整数を計算しn
ます。したがって、呼び出したsqroot(225)
場合、予想どおり 15が返されますがsqroot(15)
、3.87298 ではなく 3 が返されます。
C コードから、MIPS コードがどのようになるかを概説できます。
In calling function:
Load the number to be squared into $a0
jal root
root:
Initialize $t0 = n, $t1 = i = 0, $t2 = x = n = $a0, $t3 = n/2
Loop:
Divide n/x
Add x to n/x
Divide (x + n/x) by 2
Check if $t1 < $t3
If it is, branch back to loop
Else, move x into return register $v0
ご注意ください:
- 必要に応じて、必ずスタックをプッシュおよびポップしてください。簡単にするためにそれを省略しました。
- 2 の累乗で割る場合は、srl 命令を使用できます。
- MIPS 命令の説明と追加情報については、ここをクリックしてください。
MIPS ではありませんが、それでもアセンブリです。私が見つけた基本的なアルゴリズムは、最初の n 個の奇数の合計 = n^2 という事実に基づいていました。
したがって、プロセスを逆にして、平方根を取りたい数値から減算することでそれを利用すると、ループスルーして正確な答えまたは近似値を取得できます。完全ではない正方形のルート + 1 だと思います。
ループする回数は n であり、これは平方根です。
お役に立てれば。
mov eax, 9513135 ; eax = number to take square root of
mov ebx, eax ; make a copy of eax in ebx
loopIt :
sub ebx, count ; count starts as 1, 3, 5, 7, 9
inc count ; count = even
inc count ; count = odd
inc sqrt ; gives sqrt value
mov eax, sqrt
cmp ebx, 0
js timetoReturn ; return value if signed num, aka goes over zero
jnz loopIt
timetoReturn :
mov reg, eax ; just outputting the value
このアルゴリズムを試すと、数値の平方根以下の整数が得られます。
の平方根が必要だとしますn
。次に、次の計算を繰り返します。
x = (x + n/x) / 2
開始を選択x = n
し、x の変化が止まるまで繰り返します。
C で正の整数の平方根の下限を計算するための、理解しやすいアルゴリズムを次に示します。
int approx_sqrt(int x) {
int result;
for (int partialSum = 0, oddNum = 1; partialSum < x; partialSum += oddNum, oddNum +=2) result++;
return result;
}
少し異なる方法で、okstoryの回答と同じ原則に依存しています。
理論: partialSum がオペランドより小さい限り、徐々に増加する奇数が partialSum に追加されます。結果は、partialSum を生成するために合計された奇数の数に等しくなります。
mips で整数の平方根を計算する場合は、最初に整数を浮動小数点に変換する必要があります。平方根を取りたい数値が $t1 に格納されていると仮定すると、浮動小数点への変換は次のようになります
mtc1 $t1, $f1
cvt.s.w $f1, $f1
これで、sqrt.s 関数を使用して平方根を計算できます。
sqrt.s $f1,$f1
したがって、$f1 は $t1 に格納された整数の平方根を保持します。