平方根の計算

sqrt(平方根)の計算 - 永字八法の続き。
長いこと放っておいたけど、一応満足のいくものができたので。

Aパート

numalias sqrt_res,%0:inc %0 ; 平方根を返す数値
numalias sqrt_base,%0:inc %0 ; 平方根を求めたい数値
numalias sqrt_temp,%0:inc %0 ; 計算用変数
numalias sqrt_power,%0:inc %0 ; 二乗用変数

defsub sqrt
defsub sqrt2
defsub sqrt3

Bパート

;==================
; sqrt
;==================
; 平方根を求める。
; 第一引数:結果の平方根を格納する数値変数
; 第二引数:平方根を求めたい数値(変数)
; 平方根を返すが、端数が切り捨てられるので非常に精度が悪い。
*sqrt
getparam i%sqrt_res,%sqrt_base
mov %%sqrt_res,0 ; 設定する。
if %sqrt_base<1 return ; 負の数値は受け付けません。
mov %sqrt_temp,%sqrt_base ; 仮に置く。
*sqrt_loop
mov %sqrt_power,%sqrt_base/%sqrt_temp ; 仮の数値で元の数値を割ってみる。
notif %sqrt_power<%sqrt_temp mov %%sqrt_res,%sqrt_temp:return ; これが回答。返す。
mov %sqrt_temp,(%sqrt_temp+(%sqrt_base/%sqrt_temp))/2 ; ニュートン法による計算。
goto *sqrt_loop

;==================
; sqrt2
;==================
; 平方根を求める。ただし、結果は10倍された数値になる。
; 第一引数:結果の平方根を格納する数値変数
; 第二引数:平方根を求めたい数値(変数)
*sqrt2
getparam i%sqrt_res,%sqrt_base
sqrt %%sqrt_res,%sqrt_base*100
return

;==================
; sqrt3
;==================
; 平方根を求める。ただし、結果は100倍された数値になる。
; 第一引数:結果の平方根を格納する数値変数
; 第二引数:平方根を求めたい数値(変数)
*sqrt3
getparam i%sqrt_res,%sqrt_base
sqrt %%sqrt_res,%sqrt_base*10000
return

使い方

ニュートン法による平方根の計算関数を追加する。
sqrtは普通の平方根だが、端数は切り捨てられるので精度はかなり悪い。
sqrt2とsqrt3は平方根を10倍、100倍した数値が戻ってくる。その分、本来の小数点以下が現れてくる。
もっとも、内部では単純に元の数値を100倍、10,000倍してもう一度sqrtに与えているだけだが。
また、NScripterの特性上、正の方向には2,147,483,647を超える数値は全てマイナスになってしまうので、その場合計算できず0が戻ってくることになる。そんな計算をすることがあるかどうかはわからないが。

技術的な話

仮の平方根を二乗したらあっと言う間にオーバーフローしてしまいそうになるので、元の数値を仮の平方根で割った商を使って判定することにした。こっちの方がスマート。