mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-13 23:01:24 -07:00
big: Add factorial, have tests use hex strings.
This commit is contained in:
@@ -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,
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user