big: Add factorial, have tests use hex strings.

This commit is contained in:
Jeroen van Rijn
2021-07-31 23:25:59 +02:00
parent db0196abc7
commit e80ac18324
7 changed files with 201 additions and 135 deletions
+90 -1
View File
@@ -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;
}
}
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,
};
};
+2 -2
View File
@@ -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
+6
View File
@@ -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);
+24 -17
View File
@@ -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() {
+2 -2
View File
@@ -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.
*/
+30 -30
View File
@@ -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};
}
+47 -83
View File
@@ -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.
#