mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-22 14:25:21 +00:00
Turn core:math/bìg tests into regular core:testing tests.
`core:math/big` has been verified against Python's big integer implementation long enough. Turn it into a regular regression test using the `core:testing` framework, testing against a generated corpus of test vectors.
This commit is contained in:
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -257,12 +257,6 @@ jobs:
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\documentation
|
||||
call build.bat
|
||||
- name: core:math/big tests
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\core\math\big
|
||||
call build.bat
|
||||
- name: Odin check examples/all for Windows 32bits
|
||||
shell: cmd
|
||||
run: |
|
||||
|
||||
@@ -1660,13 +1660,13 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e
|
||||
|
||||
if internal_gte(y, x) {
|
||||
internal_swap(dest, x)
|
||||
return nil
|
||||
return internal_clamp(dest)
|
||||
}
|
||||
internal_swap(x, y)
|
||||
}
|
||||
|
||||
internal_swap(dest, x)
|
||||
return err
|
||||
return internal_clamp(dest)
|
||||
}
|
||||
internal_sqrt :: proc { internal_int_sqrt, }
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context
|
||||
res.sign = sign
|
||||
}
|
||||
|
||||
return nil
|
||||
return internal_clamp(res)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
@echo off
|
||||
rem math/big tests
|
||||
set PATH_TO_ODIN==..\..\..\..\odin
|
||||
set TEST_ARGS=-fast-tests
|
||||
set TEST_ARGS=-no-random
|
||||
set TEST_ARGS=
|
||||
set OUT_NAME=math_big_test_library.dll
|
||||
set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style
|
||||
echo ---
|
||||
echo Running core:math/big tests
|
||||
echo ---
|
||||
|
||||
%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME%
|
||||
python3 test.py %TEST_ARGS%
|
||||
|
||||
%PATH_TO_ODIN% test test_core_math_big.odin -file
|
||||
File diff suppressed because one or more lines are too long
@@ -1,362 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
An arbitrary precision mathematics implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file exports procedures for use with the test.py test suite.
|
||||
*/
|
||||
package test_core_math_big
|
||||
|
||||
/*
|
||||
TODO: Write tests for `internal_*` and test reusing parameters with the public implementations.
|
||||
*/
|
||||
|
||||
import "base:runtime"
|
||||
import "core:strings"
|
||||
import "core:math/big"
|
||||
|
||||
PyRes :: struct {
|
||||
res: cstring,
|
||||
err: big.Error,
|
||||
}
|
||||
|
||||
print_to_buffer :: proc(val: ^big.Int) -> cstring {
|
||||
context = runtime.default_context()
|
||||
r, _ := big.int_itoa_cstring(val, 16, context.allocator)
|
||||
return r
|
||||
}
|
||||
|
||||
@export test_initialize_constants :: proc "c" () -> (res: u64) {
|
||||
context = runtime.default_context()
|
||||
_ = big.initialize_constants()
|
||||
|
||||
return u64(big._DIGIT_NAILS)
|
||||
}
|
||||
|
||||
@export test_error_string :: proc "c" (err: big.Error) -> (res: cstring) {
|
||||
context = runtime.default_context()
|
||||
es := big.Error_String
|
||||
return strings.clone_to_cstring(es[err], context.allocator)
|
||||
}
|
||||
|
||||
@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
aa, bb, sum := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err} }
|
||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err} }
|
||||
if bb.used == 1 {
|
||||
if err = #force_inline big.internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} }
|
||||
} else {
|
||||
if err = #force_inline big.internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} }
|
||||
}
|
||||
|
||||
r := print_to_buffer(sum)
|
||||
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sub :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
aa, bb, sum := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(aa, bb, sum)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err} }
|
||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err} }
|
||||
if bb.used == 1 {
|
||||
if err = #force_inline big.internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} }
|
||||
} else {
|
||||
if err = #force_inline big.internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} }
|
||||
}
|
||||
|
||||
r := print_to_buffer(sum)
|
||||
if err != nil { return PyRes{res=":sub:itoa(sum):", err=err} }
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_mul :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
aa, bb, product := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(aa, bb, product)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err} }
|
||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err} }
|
||||
if err = #force_inline big.internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err} }
|
||||
|
||||
r := print_to_buffer(product)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
@export test_sqr :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
aa, square := &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(aa, square)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err} }
|
||||
if err = #force_inline big.internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err} }
|
||||
|
||||
r := print_to_buffer(square)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
NOTE(Jeroen): For simplicity, we don't return the quotient and the remainder, just the quotient.
|
||||
*/
|
||||
@export test_div :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
aa, bb, quotient := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(aa, bb, quotient)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err} }
|
||||
if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err} }
|
||||
if err = #force_inline big.internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err} }
|
||||
|
||||
r := print_to_buffer(quotient)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
res = log(a, base)
|
||||
*/
|
||||
@export test_log :: proc "c" (a: cstring, base := big.DIGIT(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
l: int
|
||||
|
||||
aa := &big.Int{}
|
||||
defer big.internal_destroy(aa)
|
||||
|
||||
if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err} }
|
||||
if l, err = #force_inline big.internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err} }
|
||||
|
||||
#force_inline big.internal_zero(aa)
|
||||
aa.digit[0] = big.DIGIT(l) & big._MASK
|
||||
aa.digit[1] = big.DIGIT(l) >> big._DIGIT_BITS
|
||||
aa.used = 2
|
||||
big.clamp(aa)
|
||||
|
||||
r := print_to_buffer(aa)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = base^power
|
||||
*/
|
||||
@export test_pow :: proc "c" (base: cstring, power := int(2)) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
dest, bb := &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(dest, bb)
|
||||
|
||||
if err = big.atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err} }
|
||||
if err = #force_inline big.internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err} }
|
||||
|
||||
r := print_to_buffer(dest)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = sqrt(src)
|
||||
*/
|
||||
@export test_sqrt :: proc "c" (source: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err} }
|
||||
if err = #force_inline big.internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = root_n(src, power)
|
||||
*/
|
||||
@export test_root_n :: proc "c" (source: cstring, power: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err} }
|
||||
if err = #force_inline big.internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_digit(src, digits)
|
||||
*/
|
||||
@export test_shr_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} }
|
||||
if err = #force_inline big._private_int_shr_leg(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl_digit(src, digits)
|
||||
*/
|
||||
@export test_shl_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} }
|
||||
if err = #force_inline big._private_int_shl_leg(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr(src, bits)
|
||||
*/
|
||||
@export test_shr :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err} }
|
||||
if err = #force_inline big.internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shr_signed(src, bits)
|
||||
*/
|
||||
@export test_shr_signed :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err} }
|
||||
if err = #force_inline big.internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = shl(src, bits)
|
||||
*/
|
||||
@export test_shl :: proc "c" (source: cstring, bits: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
src := &big.Int{}
|
||||
defer big.internal_destroy(src)
|
||||
|
||||
if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err} }
|
||||
if err = #force_inline big.internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err} }
|
||||
|
||||
r := print_to_buffer(src)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = factorial(n)
|
||||
*/
|
||||
@export test_factorial :: proc "c" (n: int) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
dest := &big.Int{}
|
||||
defer big.internal_destroy(dest)
|
||||
|
||||
if err = #force_inline big.internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err} }
|
||||
|
||||
r := print_to_buffer(dest)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = gcd(a, b)
|
||||
*/
|
||||
@export test_gcd :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
ai, bi, dest := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err} }
|
||||
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err} }
|
||||
if err = #force_inline big.internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err} }
|
||||
|
||||
r := print_to_buffer(dest)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_lcm :: proc "c" (a, b: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
|
||||
ai, bi, dest := &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.internal_destroy(ai, bi, dest)
|
||||
|
||||
if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err} }
|
||||
if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err} }
|
||||
if err = #force_inline big.internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err} }
|
||||
|
||||
r := print_to_buffer(dest)
|
||||
return PyRes{res = r, err = nil}
|
||||
}
|
||||
|
||||
/*
|
||||
dest = lcm(a, b)
|
||||
*/
|
||||
@export test_is_square :: proc "c" (a: cstring) -> (res: PyRes) {
|
||||
context = runtime.default_context()
|
||||
err: big.Error
|
||||
square: bool
|
||||
|
||||
ai := &big.Int{}
|
||||
defer big.internal_destroy(ai)
|
||||
|
||||
if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":is_square:atoi(a):", err=err} }
|
||||
if square, err = #force_inline big.internal_int_is_square(ai); err != nil { return PyRes{res=":is_square:is_square(a):", err=err} }
|
||||
|
||||
if square {
|
||||
return PyRes{"True", nil}
|
||||
}
|
||||
return PyRes{"False", nil}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package test_core_math_big
|
||||
|
||||
import "core:math/big"
|
||||
import "core:strconv"
|
||||
import "core:testing"
|
||||
|
||||
@(test)
|
||||
@@ -82,4 +83,187 @@ test_rational_to_float :: proc(t: ^testing.T) {
|
||||
testing.expect(t, err == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import "core:log"
|
||||
|
||||
@(test)
|
||||
test_big_math_vectors :: proc(t: ^testing.T) {
|
||||
for vec in big_test_vectors {
|
||||
a, b, res, expected := &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{}
|
||||
defer big.destroy(a, b, res, expected)
|
||||
|
||||
atoi(t, a, vec.a) or_continue
|
||||
atoi(t, b, vec.b) or_continue
|
||||
atoi(t, expected, vec.exp) or_continue
|
||||
|
||||
#partial switch vec.op {
|
||||
case .Add:
|
||||
err := big.add(res, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected add(%v, %v) to be %v, got %v", a, b, expected, res, err)
|
||||
|
||||
case .Sub:
|
||||
err := big.sub(res, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected sub(%v, %v) to be %v, got %v", a, b, expected, res, err)
|
||||
|
||||
case .Mul:
|
||||
err := big.mul(res, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected mul(%v, %v) to be %v, got %v", a, b, expected, res, err)
|
||||
|
||||
case .Div:
|
||||
err := big.div(res, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected div(%v, %v) to be %v, got %v", a, b, expected, res, err)
|
||||
|
||||
case .Sqr:
|
||||
err := big.sqr(res, a)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_a(t, "Expected sqr(%v) to be %v, got %v", a, expected, res, err)
|
||||
|
||||
case .Log:
|
||||
base, base_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, base_ok == true)
|
||||
|
||||
log_res, err := big.log(a, big.DIGIT(base))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
big.set(res, log_res)
|
||||
expect_ab(t, "Expected log(%v, %v) to be %v, got %v", a, b, expected, res, err)
|
||||
|
||||
case .Sqrt:
|
||||
err := big.sqrt(res, a)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_a(t, "Expected sqrt(%v) to be %v, got %v", a, expected, res, err)
|
||||
|
||||
case .Pow:
|
||||
power, power_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, power_ok == true)
|
||||
|
||||
err := big.pow(res, a, int(power))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected pow(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Root:
|
||||
n, n_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, n_ok == true)
|
||||
|
||||
err := big.root_n(res, a, int(n))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected root_n(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Shl:
|
||||
bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, bits_ok == true)
|
||||
|
||||
err := big.internal_int_shl(res, a, int(bits))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected internal_int_shl(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Shr:
|
||||
bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, bits_ok == true)
|
||||
|
||||
err := big.internal_int_shr(res, a, int(bits))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected internal_int_shr(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Shr_Signed:
|
||||
bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16)
|
||||
testing.expect(t, bits_ok == true)
|
||||
|
||||
big.set(res, a)
|
||||
err := big.internal_int_shr_signed(res, res, int(bits))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected internal_int_shr_signed(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Factorial:
|
||||
n, n_ok := strconv.parse_i64_of_base(vec.a, 16)
|
||||
testing.expect(t, n_ok == true)
|
||||
|
||||
err := big.factorial(res, int(n))
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_a(t, "Expected factorial(%v) to be '%v', got %v", a, expected, res, err)
|
||||
|
||||
case .Gcd:
|
||||
err := big.internal_int_gcd_lcm(res, nil, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected gcd(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Lcm:
|
||||
err := big.internal_int_gcd_lcm(nil, res, a, b)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
expect_ab(t, "Expected lcm(%v, %v) to be '%v', got %v", a, b, expected, res, err)
|
||||
|
||||
case .Is_Square:
|
||||
square, err := big.internal_int_is_square(a)
|
||||
testing.expect(t, err == vec.err)
|
||||
|
||||
big.set(res, 1 if square else 0)
|
||||
expect_a(t, "Expected is_square(%v) to be '%v', got %v", a, expected, res, err)
|
||||
|
||||
case:
|
||||
log.assertf(false, "Unhandled op: %v", vec.op)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect_a :: proc(t: ^testing.T, format: string, a, expected, res: ^big.Int, err: big.Error, loc := #caller_location) {
|
||||
if err != .Okay { return }
|
||||
|
||||
equal, _ := big.equals(res, expected)
|
||||
if !equal {
|
||||
as, _ := big.itoa(a)
|
||||
rs, _ := big.itoa(res)
|
||||
es, _ := big.itoa(expected)
|
||||
|
||||
defer delete(as)
|
||||
defer delete(rs)
|
||||
defer delete(es)
|
||||
|
||||
testing.expectf(t, equal, format, as, es, rs, loc=loc)
|
||||
assert(equal)
|
||||
}
|
||||
}
|
||||
|
||||
expect_ab :: proc(t: ^testing.T, format: string, a, b, expected, res: ^big.Int, err: big.Error, loc := #caller_location) {
|
||||
if err != .Okay { return }
|
||||
|
||||
equal, _ := big.equals(res, expected)
|
||||
if !equal {
|
||||
as, _ := big.itoa(a)
|
||||
bs, _ := big.itoa(b)
|
||||
rs, _ := big.itoa(res)
|
||||
es, _ := big.itoa(expected)
|
||||
|
||||
defer delete(as)
|
||||
defer delete(bs)
|
||||
defer delete(rs)
|
||||
defer delete(es)
|
||||
|
||||
testing.expectf(t, equal, format, as, bs, es, rs, loc=loc)
|
||||
assert(equal)
|
||||
}
|
||||
}
|
||||
|
||||
atoi :: proc(t: ^testing.T, i: ^big.Int, a: string, loc := #caller_location) -> bool {
|
||||
err := big.atoi(i, a, 16)
|
||||
testing.expect(t, err == .Okay, loc=loc)
|
||||
return err == .Okay
|
||||
}
|
||||
4813
tests/core/math/big/test_vectors.odin
Normal file
4813
tests/core/math/big/test_vectors.odin
Normal file
File diff suppressed because one or more lines are too long
4813
tests/core/math/test_vectors.odin
Normal file
4813
tests/core/math/test_vectors.odin
Normal file
File diff suppressed because one or more lines are too long
@@ -3,4 +3,5 @@ package tests_core
|
||||
|
||||
@(require) import "crypto"
|
||||
@(require) import "hash"
|
||||
@(require) import "image"
|
||||
@(require) import "image"
|
||||
@(require) import "math/big"
|
||||
Reference in New Issue
Block a user