sqrt関数
from マルチサイクル RISC-V CPU を作成したい
レイトレを動かすのに必要なライブラリ関数 に出てきたライブラリ関数を実装していく。
まずは平方根を求める SQRT関数から。
平方根を求めるアルゴリズムはこちらを参考にする。
https://cpplover.blogspot.com/2010/11/blog-post_20.html
code:sqrt.rb
def sqrt(s)
x = s / 2.0
last_x = 0.0
while x != last_x
last_x = x
x = (x + s / x) / 2.0
end
x
end
10.times do |i|
printf "my sqrt: %f, Ruby sqrt: %f\n", sqrt(i), Math.sqrt(i)
end
実行結果はこちら。
code:sh
$ ruby script/sqrt.rb
my sqrt: 0.000000, Ruby sqrt: 0.000000
my sqrt: 1.000000, Ruby sqrt: 1.000000
my sqrt: 1.414214, Ruby sqrt: 1.414214
my sqrt: 1.732051, Ruby sqrt: 1.732051
my sqrt: 2.000000, Ruby sqrt: 2.000000
my sqrt: 2.236068, Ruby sqrt: 2.236068
my sqrt: 2.449490, Ruby sqrt: 2.449490
my sqrt: 2.645751, Ruby sqrt: 2.645751
my sqrt: 2.828427, Ruby sqrt: 2.828427
my sqrt: 3.000000, Ruby sqrt: 3.000000
MinCamlで実装した
code:diff
diff --git a/Makefile b/Makefile
index 913c8d9..fbeacbc 100644
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ firmware/firmware.hex:
# riscv64-unknown-elf-objcopy -O verilog --verilog-data-width 4 firmware/firmware.elf firmware/firmware.hex
# MinCaml のプログラムをビルド
-FIRMWARE_TARGET = test/cos
+FIRMWARE_TARGET = test/sqrt
firmware/firmware.hex: Makefile firmware/$(FIRMWARE_TARGET).ml firmware/libmincaml.S firmware/stub.S
firmware/bin/min-caml firmware/${FIRMWARE_TARGET}
riscv64-unknown-elf-gcc -nostdlib -march=rv32if -mabi=ilp32f -Wl,-Tfirmware/custom.ld firmware/stub.S firmware/${FIRMWARE_TARGET}.s firmware/libmincaml.S -o firmware/firmware.elf
diff --git a/firmware/min-rt/min-rt.ml b/firmware/min-rt/min-rt.ml
index 17527da..761d767 100644
--- a/firmware/min-rt/min-rt.ml
+++ b/firmware/min-rt/min-rt.ml
@@ -20,7 +20,7 @@
(*MINCAML*)let rec fhalf x = x /. 2. in
(*NOMINCAML let fhalf x = x /. 2. in*)
-(**************** 三角関数 ****************)
+(**************** 三角関数とか平方根とか ****************)
(* sin 関数 *)
let rec sin x =
@@ -66,6 +66,19 @@ in
(* NOTE: 使われてるのかどうかよく分からないので、ひとまず 1.0 を返してお茶を濁す *)
let rec atan x = 1.0 in
+(* 平方根 *)
+let rec sqrt s =
+ let x = s /. 2.0 in
+ let last_x = 0.0 in
+ let rec loop x last_x s =
+ if x = last_x then
+ x
+ else
+ loop ((x +. s /. x) /. 2.0) x s
+ in
+ loop x last_x s
+in
+
(**************** ユーティリティー関数 ****************)
(* データ構造へのアクセス関数 *)
diff --git a/firmware/test/sqrt.ml b/firmware/test/sqrt.ml
new file mode 100644
index 0000000..9197a4e
--- /dev/null
+++ b/firmware/test/sqrt.ml
@@ -0,0 +1,24 @@
+(* 平方根 sqrt のテスト *)
+let rec sqrt s =
+ let x = s /. 2.0 in
+ let last_x = 0.0 in
+ let rec loop x last_x s =
+ if x = last_x then
+ x
+ else
+ loop ((x +. s /. x) /. 2.0) x s
+ in
+ loop x last_x s
+in
+(* sqrt(2) * 1000 = 1414 *)
+print_int (int_of_float (sqrt 2.0 *. 1000.0));
+print_newline ();
+(* sqrt(3) * 1000 = 1732 *)
+print_int (int_of_float (sqrt 3.0 *. 1000.0));
+print_newline ();
+(* sqrt(4) * 1000 = 2000 *)
+print_int (int_of_float (sqrt 4.0 *. 1000.0));
+print_newline ();
+(* sqrt(5) * 1000 = 2236 *)
+print_int (int_of_float (sqrt 5.0 *. 1000.0));
+print_newline ()