diff --git a/core/math/big/build.bat b/core/math/big/build.bat index 69dfe7995..6a067018e 100644 --- a/core/math/big/build.bat +++ b/core/math/big/build.bat @@ -1,7 +1,9 @@ @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: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 python test.py diff --git a/core/math/big/example.odin b/core/math/big/example.odin index ce3a0f468..056cddb90 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -13,7 +13,6 @@ package big import "core:fmt" import "core:mem" import "core:time" -// import rnd "core:math/rand" print_configation :: proc() { 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 { itoa, atoi, factorial, + lsb, + ctz, }; Event :: struct { t: time.Duration, @@ -53,7 +85,7 @@ Event :: struct { } 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(); as, err := itoa(a, base); 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); } 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 { - fmt.printf("%v\n", as); + fmt.printf("%v", as); } 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() { - 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() { @@ -102,15 +132,8 @@ main :: proc() { // print_configation(); 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 { for _, v in ta.allocation_map { diff --git a/core/math/big/test.odin b/core/math/big/test.odin index a03a7e879..0b5cdd7e9 100644 --- a/core/math/big/test.odin +++ b/core/math/big/test.odin @@ -294,3 +294,23 @@ PyRes :: struct { 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}; +} + diff --git a/core/math/big/test.py b/core/math/big/test.py index 96e0be227..efdbab607 100644 --- a/core/math/big/test.py +++ b/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_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): 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) +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. # @@ -410,6 +421,10 @@ TESTS = { test_factorial: [ [ 12_345 ], ], + test_gcd: [ + [ 123, 25, ], + [ 125, 25, ], + ], } total_passes = 0 @@ -422,9 +437,10 @@ RANDOM_TESTS = [ test_add, test_sub, test_mul, test_div, test_log, test_pow, test_sqrt, test_root_n, test_shl_digit, test_shr_digit, test_shl, test_shr_signed, + test_gcd, ] SKIP_LARGE = [ - test_pow, test_root_n, + test_pow, test_root_n, # test_gcd, ] SKIP_LARGEST = []