Browse Source

big: Test `gcd`.

Jeroen van Rijn 4 years ago
parent
commit
0028cb0258
4 changed files with 94 additions and 33 deletions
  1. 4 2
      core/math/big/build.bat
  2. 53 30
      core/math/big/example.odin
  3. 20 0
      core/math/big/test.odin
  4. 17 1
      core/math/big/test.py

+ 4 - 2
core/math/big/build.bat

@@ -1,7 +1,9 @@
 @echo off
 @echo off
-:odin run   . -vet
+:odin run . -vet
 :odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:minimal -use-separate-modules
-odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
+:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules -no-bounds-check
+:odin build . -build-mode:shared -show-timings -o:size -use-separate-modules
+:odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules -no-bounds-check
 :odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
 :odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules
 
 
 python test.py
 python test.py

+ 53 - 30
core/math/big/example.odin

@@ -13,7 +13,6 @@ package big
 import "core:fmt"
 import "core:fmt"
 import "core:mem"
 import "core:mem"
 import "core:time"
 import "core:time"
-// import rnd "core:math/rand"
 
 
 print_configation :: proc() {
 print_configation :: proc() {
 	fmt.printf(
 	fmt.printf(
@@ -42,10 +41,43 @@ _SQR_TOOM_CUTOFF,
 );
 );
 }
 }
 
 
+print_timings :: proc() {
+	fmt.printf("\nTimings:\n");
+	for v, i in Timings {
+		if v.c > 0 {
+			avg   := time.Duration(f64(v.t) / f64(v.c));
+
+			avg_s: string;
+			switch {
+			case avg < time.Microsecond:
+				avg_s = fmt.tprintf("%v ns", time.duration_nanoseconds(avg));
+			case avg < time.Millisecond:
+				avg_s = fmt.tprintf("%v µs", time.duration_microseconds(avg));
+			case:
+				avg_s = fmt.tprintf("%v", time.duration_milliseconds(avg));
+			}
+
+			total_s: string;
+			switch {
+			case v.t < time.Microsecond:
+				total_s = fmt.tprintf("%v ns", time.duration_nanoseconds(v.t));
+			case v.t < time.Millisecond:
+				total_s = fmt.tprintf("%v µs", time.duration_microseconds(v.t));
+			case:
+				total_s = fmt.tprintf("%v", time.duration_milliseconds(v.t));
+			}
+
+			fmt.printf("\t%v: %s (avg), %s (total, %v calls)\n", i, avg_s, total_s, v.c);
+		}
+	}
+}
+
 Category :: enum {
 Category :: enum {
 	itoa,
 	itoa,
 	atoi,
 	atoi,
 	factorial,
 	factorial,
+	lsb,
+	ctz,
 };
 };
 Event :: struct {
 Event :: struct {
 	t: time.Duration,
 	t: time.Duration,
@@ -53,7 +85,7 @@ Event :: struct {
 }
 }
 Timings := [Category]Event{};
 Timings := [Category]Event{};
 
 
-print :: proc(name: string, a: ^Int, base := i8(10), print_extra_info := false, print_name := false) {
+print :: proc(name: string, a: ^Int, base := i8(10), print_extra_info := false, print_name := false, newline := true) {
 	s := time.tick_now();
 	s := time.tick_now();
 	as, err := itoa(a, base);
 	as, err := itoa(a, base);
 	Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
 	Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1;
@@ -64,35 +96,33 @@ print :: proc(name: string, a: ^Int, base := i8(10), print_extra_info := false,
 		fmt.printf("%v ", name);
 		fmt.printf("%v ", name);
 	}
 	}
 	if print_extra_info {
 	if print_extra_info {
-		fmt.printf("(base: %v, bits used: %v): %v\n", base, cb, as);
+		fmt.printf("(base: %v, bits used: %v): %v", base, cb, as);
 	} else {
 	} else {
-		fmt.printf("%v\n", as);
+		fmt.printf("%v", as);
 	}
 	}
 	if err != .None {
 	if err != .None {
-		fmt.printf("%v (error: %v | %v)\n", name, err, a);
+		fmt.printf("%v (error: %v | %v)", name, err, a);
+	}
+	if newline {
+		fmt.println();
 	}
 	}
 }
 }
 
 
 demo :: proc() {
 demo :: proc() {
-	err: Error;
-	destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
-	defer destroy(destination, source, quotient, remainder, numerator, denominator);
 
 
-	a :=  "4d2";
-	b := "1538";
+	// err: Error;
+	// a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
+	// defer destroy(a, b, c, d, e, f);
 
 
-	if err = atoi(destination, a, 16); err != .None {
-		fmt.printf("atoi(a) returned %v\n", err);
-		return;
-	}
-	if err = atoi(source, b, 16); err != .None {
-		fmt.printf("atoi(b) returned %v\n", err);
-		return;
-	}
-	if err = add(destination, destination, source); err != .None {
-		fmt.printf("add(a, b) returned %v\n", err);
-		return;
-	}
+	// set(a, 25);
+	// set(b, 15);
+
+	// err = gcd(c, a, b);
+	// fmt.printf("gcd(");
+	// print("a =",   a, 10, false, true, false);
+	// print(", b =", b, 10, false, true, false);
+	// print(") =",   c, 10, false, true, false);
+	// fmt.printf(" (err = %v)\n", err);
 }
 }
 
 
 main :: proc() {
 main :: proc() {
@@ -102,15 +132,8 @@ main :: proc() {
 
 
 	// print_configation();
 	// print_configation();
 	demo();
 	demo();
+	print_timings();
 
 
-	fmt.printf("\nTimings:\n");
-	for v, i in Timings {
-		if v.c > 0 {
-			avg   := time.duration_milliseconds(time.Duration(f64(v.t) / f64(v.c)));
-			total := time.duration_milliseconds(time.Duration(v.t));
-			fmt.printf("%v: %.3f ms (avg), %.3f ms (total, %v calls)\n", i, avg, total, v.c);
-		}
-	}
 
 
 	if len(ta.allocation_map) > 0 {
 	if len(ta.allocation_map) > 0 {
 		for _, v in ta.allocation_map {
 		for _, v in ta.allocation_map {

+ 20 - 0
core/math/big/test.odin

@@ -294,3 +294,23 @@ PyRes :: struct {
 	return PyRes{res = r, err = .None};
 	return PyRes{res = r, err = .None};
 }
 }
 
 
+/*
+	dest = gcd(a, b)
+*/
+@export test_gcd :: proc "c" (a, b: cstring) -> (res: PyRes) {
+	context = runtime.default_context();
+	err: Error;
+
+	ai, bi, dest := &Int{}, &Int{}, &Int{};
+	defer destroy(ai, bi, dest);
+
+	if err = atoi(ai, string(a), 16); err != .None { return PyRes{res=":gcd:atoi(a):", err=err}; }
+	if err = atoi(bi, string(b), 16); err != .None { return PyRes{res=":gcd:atoi(b):", err=err}; }
+	if err = gcd(dest, ai, bi); err != .None { return PyRes{res=":gcd:gcd(a, b):", err=err}; }	
+
+	r: cstring;
+	r, err = int_itoa_cstring(dest, 16, context.temp_allocator);
+	if err != .None { return PyRes{res=":gcd:itoa(res):", err=err}; }
+	return PyRes{res = r, err = .None};
+}
+

+ 17 - 1
core/math/big/test.py

@@ -135,6 +135,8 @@ int_shr        = load(l.test_shr, [c_char_p, c_longlong], Res)
 int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
 int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
 
 
 int_factorial  = load(l.test_factorial, [c_uint64], Res)
 int_factorial  = load(l.test_factorial, [c_uint64], Res)
+int_gcd        = load(l.test_gcd, [c_char_p, c_char_p], Res)
+
 
 
 def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16):
 def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16):
 	passed = True
 	passed = True
@@ -332,6 +334,15 @@ def test_factorial(n = 0, expected_error = Error.Okay):
 		
 		
 	return test("test_factorial", res, [n], expected_error, expected_result)
 	return test("test_factorial", res, [n], expected_error, expected_result)
 
 
+def test_gcd(a = 0, b = 0, expected_error = Error.Okay):
+	args  = [arg_to_odin(a), arg_to_odin(b)]
+	res   = int_gcd(*args)
+	expected_result = None
+	if expected_error == Error.Okay:
+		expected_result = math.gcd(a, b)
+		
+	return test("test_gcd", res, [a, b], expected_error, expected_result)
+
 
 
 # TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on.
 # TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on.
 #
 #
@@ -410,6 +421,10 @@ TESTS = {
 	test_factorial: [
 	test_factorial: [
 		[ 12_345 ],
 		[ 12_345 ],
 	],
 	],
+	test_gcd: [
+		[ 123, 25, ],
+		[ 125, 25, ],
+	],
 }
 }
 
 
 total_passes   = 0
 total_passes   = 0
@@ -422,9 +437,10 @@ RANDOM_TESTS = [
 	test_add, test_sub, test_mul, test_div,
 	test_add, test_sub, test_mul, test_div,
 	test_log, test_pow, test_sqrt, test_root_n,
 	test_log, test_pow, test_sqrt, test_root_n,
 	test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
 	test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
+	test_gcd,
 ]
 ]
 SKIP_LARGE   = [
 SKIP_LARGE   = [
-	test_pow, test_root_n,
+	test_pow, test_root_n, # test_gcd,
 ]
 ]
 SKIP_LARGEST = []
 SKIP_LARGEST = []