From e80ac183246a1481926f838b5f1e5588410c2248 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 31 Jul 2021 23:25:59 +0200 Subject: [PATCH] big: Add `factorial`, have tests use hex strings. --- core/math/big/basic.odin | 91 +++++++++++++++++++++++++- core/math/big/build.bat | 4 +- core/math/big/common.odin | 6 ++ core/math/big/example.odin | 41 +++++++----- core/math/big/radix.odin | 4 +- core/math/big/test.odin | 60 ++++++++--------- core/math/big/test.py | 130 ++++++++++++++----------------------- 7 files changed, 201 insertions(+), 135 deletions(-) diff --git a/core/math/big/basic.odin b/core/math/big/basic.odin index fde11eba6..1ba5807f4 100644 --- a/core/math/big/basic.odin +++ b/core/math/big/basic.odin @@ -749,6 +749,30 @@ int_sqrmod :: proc(remainder, number, modulus: ^Int) -> (err: Error) { } sqrmod :: proc { int_sqrmod, }; + +int_factorial :: proc(res: ^Int, n: DIGIT) -> (err: Error) { + if n < 0 { return .Invalid_Argument; } + + i := DIGIT(len(_factorial_table)); + if n < i { + return set(res, _factorial_table[n]); + } + + a := &Int{}; + defer destroy(a); + + if err = set( a, i - 1); err != .None { return err; } + if err = set(res, _factorial_table[i - 1]); err != .None { return err; } + + for { + if err = mul(res, res, DIGIT(i)); err != .None || i == n { return err; } + i += 1; + } + + return .None; +} +factorial :: proc { int_factorial, }; + /* ========================== Low-level routines @@ -1237,4 +1261,69 @@ _int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT) -> (remain } destroy(q); return remainder, .None; -} \ No newline at end of file +} + + +when size_of(rawptr) == 8 { + _factorial_table := [35]_WORD{ +/* f(00): */ 1, +/* f(01): */ 1, +/* f(02): */ 2, +/* f(03): */ 6, +/* f(04): */ 24, +/* f(05): */ 120, +/* f(06): */ 720, +/* f(07): */ 5_040, +/* f(08): */ 40_320, +/* f(09): */ 362_880, +/* f(10): */ 3_628_800, +/* f(11): */ 39_916_800, +/* f(12): */ 479_001_600, +/* f(13): */ 6_227_020_800, +/* f(14): */ 87_178_291_200, +/* f(15): */ 1_307_674_368_000, +/* f(16): */ 20_922_789_888_000, +/* f(17): */ 355_687_428_096_000, +/* f(18): */ 6_402_373_705_728_000, +/* f(19): */ 121_645_100_408_832_000, +/* f(20): */ 2_432_902_008_176_640_000, +/* f(21): */ 51_090_942_171_709_440_000, +/* f(22): */ 1_124_000_727_777_607_680_000, +/* f(23): */ 25_852_016_738_884_976_640_000, +/* f(24): */ 620_448_401_733_239_439_360_000, +/* f(25): */ 15_511_210_043_330_985_984_000_000, +/* f(26): */ 403_291_461_126_605_635_584_000_000, +/* f(27): */ 10_888_869_450_418_352_160_768_000_000, +/* f(28): */ 304_888_344_611_713_860_501_504_000_000, +/* f(29): */ 8_841_761_993_739_701_954_543_616_000_000, +/* f(30): */ 265_252_859_812_191_058_636_308_480_000_000, +/* f(31): */ 8_222_838_654_177_922_817_725_562_880_000_000, +/* f(32): */ 263_130_836_933_693_530_167_218_012_160_000_000, +/* f(33): */ 8_683_317_618_811_886_495_518_194_401_280_000_000, +/* f(34): */ 295_232_799_039_604_140_847_618_609_643_520_000_000, + }; +} else { + _factorial_table := [21]_WORD{ +/* f(00): */ 1, +/* f(01): */ 1, +/* f(02): */ 2, +/* f(03): */ 6, +/* f(04): */ 24, +/* f(05): */ 120, +/* f(06): */ 720, +/* f(07): */ 5_040, +/* f(08): */ 40_320, +/* f(09): */ 362_880, +/* f(10): */ 3_628_800, +/* f(11): */ 39_916_800, +/* f(12): */ 479_001_600, +/* f(13): */ 6_227_020_800, +/* f(14): */ 87_178_291_200, +/* f(15): */ 1_307_674_368_000, +/* f(16): */ 20_922_789_888_000, +/* f(17): */ 355_687_428_096_000, +/* f(18): */ 6_402_373_705_728_000, +/* f(19): */ 121_645_100_408_832_000, +/* f(20): */ 2_432_902_008_176_640_000, + }; +}; \ No newline at end of file diff --git a/core/math/big/build.bat b/core/math/big/build.bat index 69dfe7995..2a21e4f98 100644 --- a/core/math/big/build.bat +++ b/core/math/big/build.bat @@ -1,7 +1,7 @@ @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 :odin build . -build-mode:shared -show-timings -o:speed -use-separate-modules python test.py diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 32d7b938f..5bdc0139f 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -11,6 +11,11 @@ package big import "core:intrinsics" +/* + TODO: Make the tunables runtime adjustable where practical. + This allows to benchmark and/or setting optimized values for a certain CPU without recompiling. +*/ + /* Tunables */ @@ -21,6 +26,7 @@ when _LOW_MEMORY { _DEFAULT_DIGIT_COUNT :: 32; } + _MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF); _SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, _DEFAULT_SQR_KARATSUBA_CUTOFF); _MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, _DEFAULT_MUL_TOOM_CUTOFF); diff --git a/core/math/big/example.odin b/core/math/big/example.odin index 0c8ef35e1..ce3a0f468 100644 --- a/core/math/big/example.odin +++ b/core/math/big/example.odin @@ -45,6 +45,7 @@ _SQR_TOOM_CUTOFF, Category :: enum { itoa, atoi, + factorial, }; Event :: struct { t: time.Duration, @@ -52,14 +53,21 @@ Event :: struct { } Timings := [Category]Event{}; -print :: proc(name: string, a: ^Int, base := i8(10)) { +print :: proc(name: string, a: ^Int, base := i8(10), print_extra_info := false, print_name := false) { s := time.tick_now(); as, err := itoa(a, base); Timings[.itoa].t += time.tick_since(s); Timings[.itoa].c += 1; defer delete(as); cb, _ := count_bits(a); - fmt.printf("%v (base: %v, bits used: %v): %v\n", name, base, cb, as); + if print_name { + fmt.printf("%v ", name); + } + if print_extra_info { + fmt.printf("(base: %v, bits used: %v): %v\n", base, cb, as); + } else { + fmt.printf("%v\n", as); + } if err != .None { fmt.printf("%v (error: %v | %v)\n", name, err, a); } @@ -70,22 +78,21 @@ demo :: proc() { destination, source, quotient, remainder, numerator, denominator := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}; defer destroy(destination, source, quotient, remainder, numerator, denominator); - err = atoi(source, "711456452774621215865929644892071691538299606591173717356248653735056872543694196490784640730887936656406546625676792022", 10); - print("src ", source); + a := "4d2"; + b := "1538"; - fmt.println("sqrt should be 843478780275248664696797599030708027195155136953848512749494"); - - fmt.println(); - err = sqrt(destination, source); - fmt.printf("sqrt returned: %v\n", err); - print("sqrt ", destination); - - err = atoi(denominator, "711456452774621215865929644892071691538299606591173717356248653735056872543694196490784640730887936656406546625676792022", 10); - err = root_n(quotient, denominator, 2); - fmt.printf("root_n(2) returned: %v\n", err); - print("root_n(2)", quotient); - - // fmt.println(); + 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; + } } main :: proc() { diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 572adec6a..ef5b0079e 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -240,6 +240,7 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8) -> (err: Error) { /* Make sure the radix is ok. */ + if radix < 2 || radix > 64 { return .Invalid_Argument; } @@ -278,7 +279,7 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8) -> (err: Error) { ch = rune(input[0]); if radix <= 36 && ch >= 'a' && ch <= 'z' { - ch += 'a' - 'A'; + ch -= 32; // 'a' - 'A' } pos := ch - '+'; @@ -299,7 +300,6 @@ int_atoi :: proc(res: ^Int, input: string, radix: i8) -> (err: Error) { input = input[1:]; } - /* If an illegal character was found, fail. */ diff --git a/core/math/big/test.odin b/core/math/big/test.odin index ed95669f5..b8643813c 100644 --- a/core/math/big/test.odin +++ b/core/math/big/test.odin @@ -33,12 +33,12 @@ PyRes :: struct { aa, bb, sum := &Int{}, &Int{}, &Int{}; defer destroy(aa, bb, sum); - if err = atoi(aa, string(a), 10); err != .None { return PyRes{res=":add:atoi(a):", err=err}; } - if err = atoi(bb, string(b), 10); err != .None { return PyRes{res=":add:atoi(b):", err=err}; } + if err = atoi(aa, string(a), 16); err != .None { return PyRes{res=":add:atoi(a):", err=err}; } + if err = atoi(bb, string(b), 16); err != .None { return PyRes{res=":add:atoi(b):", err=err}; } if err = add(sum, aa, bb); err != .None { return PyRes{res=":add:add(sum,a,b):", err=err}; } r: cstring; - r, err = int_itoa_cstring(sum, 10, context.temp_allocator); + r, err = int_itoa_cstring(sum, 16, context.temp_allocator); if err != .None { return PyRes{res=":add:itoa(sum):", err=err}; } return PyRes{res = r, err = .None}; } @@ -50,12 +50,12 @@ PyRes :: struct { aa, bb, sum := &Int{}, &Int{}, &Int{}; defer destroy(aa, bb, sum); - if err = atoi(aa, string(a), 10); err != .None { return PyRes{res=":sub:atoi(a):", err=err}; } - if err = atoi(bb, string(b), 10); err != .None { return PyRes{res=":sub:atoi(b):", err=err}; } + if err = atoi(aa, string(a), 16); err != .None { return PyRes{res=":sub:atoi(a):", err=err}; } + if err = atoi(bb, string(b), 16); err != .None { return PyRes{res=":sub:atoi(b):", err=err}; } if err = sub(sum, aa, bb); err != .None { return PyRes{res=":sub:sub(sum,a,b):", err=err}; } r: cstring; - r, err = int_itoa_cstring(sum, 10, context.temp_allocator); + r, err = int_itoa_cstring(sum, 16, context.temp_allocator); if err != .None { return PyRes{res=":sub:itoa(sum):", err=err}; } return PyRes{res = r, err = .None}; } @@ -67,12 +67,12 @@ PyRes :: struct { aa, bb, product := &Int{}, &Int{}, &Int{}; defer destroy(aa, bb, product); - if err = atoi(aa, string(a), 10); err != .None { return PyRes{res=":mul:atoi(a):", err=err}; } - if err = atoi(bb, string(b), 10); err != .None { return PyRes{res=":mul:atoi(b):", err=err}; } + if err = atoi(aa, string(a), 16); err != .None { return PyRes{res=":mul:atoi(a):", err=err}; } + if err = atoi(bb, string(b), 16); err != .None { return PyRes{res=":mul:atoi(b):", err=err}; } if err = mul(product, aa, bb); err != .None { return PyRes{res=":mul:mul(product,a,b):", err=err}; } r: cstring; - r, err = int_itoa_cstring(product, 10, context.temp_allocator); + r, err = int_itoa_cstring(product, 16, context.temp_allocator); if err != .None { return PyRes{res=":mul:itoa(product):", err=err}; } return PyRes{res = r, err = .None}; } @@ -87,12 +87,12 @@ PyRes :: struct { aa, bb, quotient := &Int{}, &Int{}, &Int{}; defer destroy(aa, bb, quotient); - if err = atoi(aa, string(a), 10); err != .None { return PyRes{res=":div:atoi(a):", err=err}; } - if err = atoi(bb, string(b), 10); err != .None { return PyRes{res=":div:atoi(b):", err=err}; } + if err = atoi(aa, string(a), 16); err != .None { return PyRes{res=":div:atoi(a):", err=err}; } + if err = atoi(bb, string(b), 16); err != .None { return PyRes{res=":div:atoi(b):", err=err}; } if err = div(quotient, aa, bb); err != .None { return PyRes{res=":div:div(quotient,a,b):", err=err}; } r: cstring; - r, err = int_itoa_cstring(quotient, 10, context.temp_allocator); + r, err = int_itoa_cstring(quotient, 16, context.temp_allocator); if err != .None { return PyRes{res=":div:itoa(quotient):", err=err}; } return PyRes{res = r, err = .None}; } @@ -109,7 +109,7 @@ PyRes :: struct { aa := &Int{}; defer destroy(aa); - if err = atoi(aa, string(a), 10); err != .None { return PyRes{res=":log:atoi(a):", err=err}; } + if err = atoi(aa, string(a), 16); err != .None { return PyRes{res=":log:atoi(a):", err=err}; } if l, err = log(aa, base); err != .None { return PyRes{res=":log:log(a, base):", err=err}; } zero(aa); @@ -119,7 +119,7 @@ PyRes :: struct { clamp(aa); r: cstring; - r, err = int_itoa_cstring(aa, 10, context.temp_allocator); + r, err = int_itoa_cstring(aa, 16, context.temp_allocator); if err != .None { return PyRes{res=":log:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -134,11 +134,11 @@ PyRes :: struct { dest, bb := &Int{}, &Int{}; defer destroy(dest, bb); - if err = atoi(bb, string(base), 10); err != .None { return PyRes{res=":pow:atoi(base):", err=err}; } + if err = atoi(bb, string(base), 16); err != .None { return PyRes{res=":pow:atoi(base):", err=err}; } if err = pow(dest, bb, power); err != .None { return PyRes{res=":pow:pow(dest, base, power):", err=err}; } r: cstring; - r, err = int_itoa_cstring(dest, 10, context.temp_allocator); + r, err = int_itoa_cstring(dest, 16, context.temp_allocator); if err != .None { return PyRes{res=":log:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -153,11 +153,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":sqrt:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":sqrt:atoi(src):", err=err}; } if err = sqrt(src, src); err != .None { return PyRes{res=":sqrt:sqrt(src):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":log:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -172,11 +172,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":root_n:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":root_n:atoi(src):", err=err}; } if err = root_n(src, src, power); err != .None { return PyRes{res=":root_n:root_n(src):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":root_n:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -191,11 +191,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":shr_digit:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":shr_digit:atoi(src):", err=err}; } if err = shr_digit(src, digits); err != .None { return PyRes{res=":shr_digit:shr_digit(src):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":shr_digit:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -210,11 +210,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":shl_digit:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":shl_digit:atoi(src):", err=err}; } if err = shl_digit(src, digits); err != .None { return PyRes{res=":shl_digit:shr_digit(src):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":shl_digit:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -229,11 +229,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":shr:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":shr:atoi(src):", err=err}; } if err = shr(src, src, bits); err != .None { return PyRes{res=":shr:shr(src, bits):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":shr:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -248,11 +248,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":shr_signed:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":shr_signed:atoi(src):", err=err}; } if err = shr_signed(src, src, bits); err != .None { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":shr_signed:itoa(res):", err=err}; } return PyRes{res = r, err = .None}; } @@ -267,11 +267,11 @@ PyRes :: struct { src := &Int{}; defer destroy(src); - if err = atoi(src, string(source), 10); err != .None { return PyRes{res=":shl:atoi(src):", err=err}; } + if err = atoi(src, string(source), 16); err != .None { return PyRes{res=":shl:atoi(src):", err=err}; } if err = shl(src, src, bits); err != .None { return PyRes{res=":shl:shl(src, bits):", err=err}; } r: cstring; - r, err = int_itoa_cstring(src, 10, context.temp_allocator); + r, err = int_itoa_cstring(src, 16, context.temp_allocator); if err != .None { return PyRes{res=":shl: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 645383b0f..abfa42336 100644 --- a/core/math/big/test.py +++ b/core/math/big/test.py @@ -134,7 +134,7 @@ int_shl = load(l.test_shl, [c_char_p, c_longlong], Res) 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) -def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = ""): +def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16): passed = True r = None err = Error(res.err) @@ -152,7 +152,7 @@ def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expecte r = None try: r = res.res.decode('utf-8') - r = int(res.res, 10) + r = int(res.res, radix) except: pass @@ -168,42 +168,40 @@ def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expecte return passed +def arg_to_odin(a): + if a >= 0: + s = hex(a)[2:] + else: + s = '-' + hex(a)[3:] + return s.encode('utf-8') def test_add(a = 0, b = 0, expected_error = Error.Okay): - args = [str(a), str(b)] - sa_c, sb_c = args[0].encode('utf-8'), args[1].encode('utf-8') - res = add(sa_c, sb_c) + args = [arg_to_odin(a), arg_to_odin(b)] + res = add(*args) expected_result = None if expected_error == Error.Okay: expected_result = a + b - return test("test_add", res, args, expected_error, expected_result) + return test("test_add", res, [a, b], expected_error, expected_result) def test_sub(a = 0, b = 0, expected_error = Error.Okay): - sa, sb = str(a), str(b) - sa_c, sb_c = sa.encode('utf-8'), sb.encode('utf-8') - res = sub(sa_c, sb_c) + args = [arg_to_odin(a), arg_to_odin(b)] + res = sub(*args) expected_result = None if expected_error == Error.Okay: expected_result = a - b - return test("test_sub", res, [sa_c, sb_c], expected_error, expected_result) + return test("test_sub", res, [a, b], expected_error, expected_result) def test_mul(a = 0, b = 0, expected_error = Error.Okay): - sa, sb = str(a), str(b) - sa_c, sb_c = sa.encode('utf-8'), sb.encode('utf-8') - res = mul(sa_c, sb_c) + args = [arg_to_odin(a), arg_to_odin(b)] + res = mul(*args) expected_result = None if expected_error == Error.Okay: expected_result = a * b - return test("test_mul", res, [sa_c, sb_c], expected_error, expected_result) + return test("test_mul", res, [a, b], expected_error, expected_result) def test_div(a = 0, b = 0, expected_error = Error.Okay): - sa, sb = str(a), str(b) - sa_c, sb_c = sa.encode('utf-8'), sb.encode('utf-8') - try: - res = div(sa_c, sb_c) - except: - print("Exception with arguments:", a, b) - return False + args = [arg_to_odin(a), arg_to_odin(b)] + res = div(*args) expected_result = None if expected_error == Error.Okay: # @@ -215,23 +213,21 @@ def test_div(a = 0, b = 0, expected_error = Error.Okay): expected_result = int(-(a // abs((b)))) else: expected_result = a // b if b != 0 else None - return test("test_div", res, [sa_c, sb_c], expected_error, expected_result) + return test("test_div", res, [a, b], expected_error, expected_result) def test_log(a = 0, base = 0, expected_error = Error.Okay): - args = [str(a), base] - sa_c = args[0].encode('utf-8') - res = int_log(sa_c, base) + args = [arg_to_odin(a), base] + res = int_log(*args) expected_result = None if expected_error == Error.Okay: expected_result = int(math.log(a, base)) - return test("test_log", res, args, expected_error, expected_result) + return test("test_log", res, [a, base], expected_error, expected_result) def test_pow(base = 0, power = 0, expected_error = Error.Okay): - args = [str(base), power] - sa_c = args[0].encode('utf-8') - res = int_pow(sa_c, power) + args = [arg_to_odin(base), power] + res = int_pow(*args) expected_result = None if expected_error == Error.Okay: @@ -241,23 +237,18 @@ def test_pow(base = 0, power = 0, expected_error = Error.Okay): # NOTE(Jeroen): Don't use `math.pow`, it's a floating point approximation. # Use built-in `pow` or `a**b` instead. expected_result = pow(base, power) - return test("test_pow", res, args, expected_error, expected_result) + return test("test_pow", res, [base, power], expected_error, expected_result) def test_sqrt(number = 0, expected_error = Error.Okay): - args = [str(number)] - sa_c = args[0].encode('utf-8') - try: - res = int_sqrt(sa_c) - except: - print("sqrt:", number) - + args = [arg_to_odin(number)] + res = int_sqrt(*args) expected_result = None if expected_error == Error.Okay: if number < 0: expected_result = 0 else: expected_result = int(math.isqrt(number)) - return test("test_sqrt", res, args, expected_error, expected_result) + return test("test_sqrt", res, [number], expected_error, expected_result) def root_n(number, root): u, s = number, number + 1 @@ -268,13 +259,8 @@ def root_n(number, root): return s def test_root_n(number = 0, root = 0, expected_error = Error.Okay): - args = [str(number), root] - sa_c = args[0].encode('utf-8') - try: - res = int_root_n(sa_c, root) - except: - print("root_n:", number, root) - + args = [arg_to_odin(number), root] + res = int_root_n(*args) expected_result = None if expected_error == Error.Okay: if number < 0: @@ -282,27 +268,19 @@ def test_root_n(number = 0, root = 0, expected_error = Error.Okay): else: expected_result = root_n(number, root) - return test("test_root_n", res, args, expected_error, expected_result) + return test("test_root_n", res, [number, root], expected_error, expected_result) def test_shl_digit(a = 0, digits = 0, expected_error = Error.Okay): - args = [str(a), digits] - sa_c = args[0].encode('utf-8') - res = int_shl_digit(sa_c, digits) - + args = [arg_to_odin(a), digits] + res = int_shl_digit(*args) expected_result = None if expected_error == Error.Okay: expected_result = a << (digits * 60) - return test("test_shl_digit", res, args, expected_error, expected_result) + return test("test_shl_digit", res, [a, digits], expected_error, expected_result) def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay): - args = [str(a), digits] - sa_c = args[0].encode('utf-8') - try: - res = int_shr_digit(sa_c, digits) - except: - print("int_shr_digit", a, digits) - exit() - + args = [arg_to_odin(a), digits] + res = int_shr_digit(*args) expected_result = None if expected_error == Error.Okay: if a < 0: @@ -311,27 +289,19 @@ def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay): else: expected_result = a >> (digits * 60) - return test("test_shr_digit", res, args, expected_error, expected_result) + return test("test_shr_digit", res, [a, digits], expected_error, expected_result) def test_shl(a = 0, bits = 0, expected_error = Error.Okay): - args = [str(a), bits] - sa_c = args[0].encode('utf-8') - res = int_shl(sa_c, bits) - + args = [arg_to_odin(a), bits] + res = int_shl(*args) expected_result = None if expected_error == Error.Okay: expected_result = a << bits - return test("test_shl", res, args, expected_error, expected_result) + return test("test_shl", res, [a, bits], expected_error, expected_result) def test_shr(a = 0, bits = 0, expected_error = Error.Okay): - args = [str(a), bits] - sa_c = args[0].encode('utf-8') - try: - res = int_shr(sa_c, bits) - except: - print("int_shr", a, bits) - exit() - + args = [arg_to_odin(a), bits] + res = int_shr(*args) expected_result = None if expected_error == Error.Okay: if a < 0: @@ -340,22 +310,16 @@ def test_shr(a = 0, bits = 0, expected_error = Error.Okay): else: expected_result = a >> bits - return test("test_shr", res, args, expected_error, expected_result) + return test("test_shr", res, [a, bits], expected_error, expected_result) def test_shr_signed(a = 0, bits = 0, expected_error = Error.Okay): - args = [str(a), bits] - sa_c = args[0].encode('utf-8') - try: - res = int_shr_signed(sa_c, bits) - except: - print("int_shr_signed", a, bits) - exit() - + args = [arg_to_odin(a), bits] + res = int_shr_signed(*args) expected_result = None if expected_error == Error.Okay: expected_result = a >> bits - return test("test_shr_signed", res, args, expected_error, expected_result) + return test("test_shr_signed", res, [a, bits], expected_error, expected_result) # TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on. #