Merge branch 'master' of https://github.com/odin-lang/Odin
This commit is contained in:
commit
c3a64c2a59
25 files changed
+891
-153
No files matched your search
@@ -8,31 +8,31 @@ CC=clang
|
|||||||
OS=$(shell uname)
|
OS=$(shell uname)
|
||||||
|
|
||||||
ifeq ($(OS), Darwin)
|
ifeq ($(OS), Darwin)
|
||||||
LLVM_CONFIG=llvm-config
|
LLVM_CONFIG=llvm-config
|
||||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||||
LLVM_CONFIG=llvm-config
|
LLVM_CONFIG=llvm-config
|
||||||
else
|
else
|
||||||
$(error "Requirement: llvm-config must be version 11")
|
$(error "Requirement: llvm-config must be version 11")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LDFLAGS:=$(LDFLAGS) -liconv
|
LDFLAGS:=$(LDFLAGS) -liconv
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||||
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
LDFLAGS:=$(LDFLAGS) -lLLVM-C
|
||||||
endif
|
endif
|
||||||
ifeq ($(OS), Linux)
|
ifeq ($(OS), Linux)
|
||||||
LLVM_CONFIG=llvm-config-11
|
LLVM_CONFIG=llvm-config-11
|
||||||
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
ifneq ($(shell which llvm-config-11 2>/dev/null),)
|
||||||
LLVM_CONFIG=llvm-config-11
|
LLVM_CONFIG=llvm-config-11
|
||||||
else
|
else
|
||||||
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
ifneq ($(shell llvm-config --version | grep '^11\.'),)
|
||||||
LLVM_CONFIG=llvm-config
|
LLVM_CONFIG=llvm-config
|
||||||
else
|
else
|
||||||
$(error "Requirement: llvm-config must be version 11")
|
$(error "Requirement: llvm-config must be version 11")
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: debug demo
|
all: debug demo
|
||||||
@@ -51,6 +51,3 @@ release_native:
|
|||||||
|
|
||||||
nightly:
|
nightly:
|
||||||
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
$(CC) src/main.cpp src/libtommath.cpp $(DISABLED_WARNINGS) $(CFLAGS) -DNIGHTLY -O3 $(LDFLAGS) -o odin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.3 Complex arithmetic
|
// 7.3 Complex arithmetic
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
// 7.4 Character handling
|
// 7.4 Character handling
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.5 Errors
|
// 7.5 Errors
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
// C11 standard only requires the definition of:
|
// C11 standard only requires the definition of:
|
||||||
// EDOM,
|
// EDOM,
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ package libc
|
|||||||
|
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
// To support C's tgmath behavior we use Odin's explicit procedure overloading,
|
// To support C's tgmath behavior we use Odin's explicit procedure overloading,
|
||||||
// but we cannot use the same names as exported by libc so use @(link_name)
|
// but we cannot use the same names as exported by libc so use @(link_name)
|
||||||
|
|||||||
+43
-9
@@ -2,18 +2,52 @@ package libc
|
|||||||
|
|
||||||
// 7.13 Nonlocal jumps
|
// 7.13 Nonlocal jumps
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == "windows" {
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
// 7.13.1 Save calling environment
|
||||||
|
//
|
||||||
|
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
|
||||||
|
// necessarily export a symbol named setjmp but rather _setjmp in the case
|
||||||
|
// of musl, glibc, BSD libc, and msvcrt.
|
||||||
|
//
|
||||||
|
/// NOTE(dweiler): UCRT has two implementations of longjmp. One that performs
|
||||||
|
// stack unwinding and one that doesn't. The choice of which to use depends on a
|
||||||
|
// flag which is set inside the jmp_buf structure given to setjmp. The default
|
||||||
|
// behavior is to unwind the stack. Within Odin, we cannot use the stack
|
||||||
|
// unwinding version as the unwinding information isn't present. To opt-in to
|
||||||
|
// the regular non-unwinding version we need a way to set this flag. Since the
|
||||||
|
// location of the flag within the struct is not defined or part of the ABI and
|
||||||
|
// can change between versions of UCRT, we must rely on setjmp to set it. It
|
||||||
|
// turns out that setjmp receives this flag in the RDX register on Win64, this
|
||||||
|
// just so happens to coincide with the second argument of a function in the
|
||||||
|
// Win64 ABI. By giving our setjmp a second argument with the value of zero,
|
||||||
|
// the RDX register will contain zero and correctly set the flag to disable
|
||||||
|
// stack unwinding.
|
||||||
|
@(link_name="_setjmp")
|
||||||
|
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
@(default_calling_convention="c")
|
||||||
|
foreign libc {
|
||||||
|
// 7.13.1 Save calling environment
|
||||||
|
//
|
||||||
|
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
|
||||||
|
// necessarily export a symbol named setjmp but rather _setjmp in the case
|
||||||
|
// of musl, glibc, BSD libc, and msvcrt.
|
||||||
|
@(link_name="_setjmp")
|
||||||
|
setjmp :: proc(env: ^jmp_buf) -> int ---;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.13.1 Save calling environment
|
|
||||||
//
|
|
||||||
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
|
|
||||||
// necessarily export a symbol named setjmp but rather _setjmp in the case
|
|
||||||
// of musl, glibc, BSD libc, and msvcrt.
|
|
||||||
@(link_name="_setjmp")
|
|
||||||
setjmp :: proc(env: ^jmp_buf) -> int ---;
|
|
||||||
|
|
||||||
// 7.13.2 Restore calling environment
|
// 7.13.2 Restore calling environment
|
||||||
longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---;
|
longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.14 Signal handling
|
// 7.14 Signal handling
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
sig_atomic_t :: distinct atomic_int;
|
sig_atomic_t :: distinct atomic_int;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package libc
|
package libc
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
// 7.21 Input/output
|
// 7.21 Input/output
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.22 General utilities
|
// 7.22 General utilities
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
RAND_MAX :: 0x7fff;
|
RAND_MAX :: 0x7fff;
|
||||||
@@ -14,7 +18,7 @@ when ODIN_OS == "windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MB_CUR_MAX :: #force_inline proc() -> size_t {
|
MB_CUR_MAX :: #force_inline proc() -> size_t {
|
||||||
return ___mb_cur_max_func();
|
return size_t(___mb_cur_max_func());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,11 @@ package libc
|
|||||||
|
|
||||||
// 7.24 String handling
|
// 7.24 String handling
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
foreign libc {
|
foreign libc {
|
||||||
// 7.24.2 Copying functions
|
// 7.24.2 Copying functions
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package libc_tests
|
||||||
|
|
||||||
|
import "core:c/libc"
|
||||||
|
|
||||||
|
test_stdio :: proc() {
|
||||||
|
c: libc.char = 'C';
|
||||||
|
libc.puts("Hello from puts");
|
||||||
|
libc.printf("Hello from printf in %c\n", c);
|
||||||
|
}
|
||||||
|
test_thread :: proc() {
|
||||||
|
thread_proc :: proc "c" (rawptr) -> libc.int {
|
||||||
|
libc.printf("Hello from thread");
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
thread: libc.thrd_t;
|
||||||
|
libc.thrd_create(&thread, thread_proc, nil);
|
||||||
|
result: libc.int;
|
||||||
|
libc.thrd_join(thread, &result);
|
||||||
|
libc.printf(" %d\n", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
jmp: libc.jmp_buf;
|
||||||
|
test_sjlj :: proc() {
|
||||||
|
if libc.setjmp(&jmp) != 0 {
|
||||||
|
libc.printf("Hello from longjmp\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
libc.printf("Hello from setjmp\n");
|
||||||
|
libc.longjmp(&jmp, 1);
|
||||||
|
}
|
||||||
|
test_signal :: proc() {
|
||||||
|
handler :: proc "c" (sig: libc.int) {
|
||||||
|
libc.printf("Hello from signal handler\n");
|
||||||
|
}
|
||||||
|
libc.signal(libc.SIGABRT, handler);
|
||||||
|
libc.raise(libc.SIGABRT);
|
||||||
|
}
|
||||||
|
test_atexit :: proc() {
|
||||||
|
handler :: proc "c" () {
|
||||||
|
libc.printf("Hello from atexit\n");
|
||||||
|
}
|
||||||
|
libc.atexit(handler);
|
||||||
|
}
|
||||||
|
main :: proc() {
|
||||||
|
test_stdio();
|
||||||
|
test_thread();
|
||||||
|
test_sjlj();
|
||||||
|
test_signal();
|
||||||
|
test_atexit();
|
||||||
|
}
|
||||||
@@ -6,7 +6,10 @@ thrd_start_t :: proc "c" (rawptr) -> int;
|
|||||||
tss_dtor_t :: proc "c" (rawptr);
|
tss_dtor_t :: proc "c" (rawptr);
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
foreign import libc "system:c"
|
foreign import libc {
|
||||||
|
"system:libucrt.lib",
|
||||||
|
"system:msvcprt.lib"
|
||||||
|
}
|
||||||
|
|
||||||
thrd_success :: 0; // _Thrd_success
|
thrd_success :: 0; // _Thrd_success
|
||||||
thrd_nomem :: 1; // _Thrd_nomem
|
thrd_nomem :: 1; // _Thrd_nomem
|
||||||
@@ -24,6 +27,7 @@ when ODIN_OS == "windows" {
|
|||||||
thrd_t :: struct { _: rawptr, _: uint, } // _Thrd_t
|
thrd_t :: struct { _: rawptr, _: uint, } // _Thrd_t
|
||||||
tss_t :: distinct int; // _Tss_imp_t
|
tss_t :: distinct int; // _Tss_imp_t
|
||||||
cnd_t :: distinct rawptr; // _Cnd_imp_t
|
cnd_t :: distinct rawptr; // _Cnd_imp_t
|
||||||
|
mtx_t :: distinct rawptr; // _Mtx_imp_t
|
||||||
|
|
||||||
// MSVCRT does not expose the C11 symbol names as what they are in C11
|
// MSVCRT does not expose the C11 symbol names as what they are in C11
|
||||||
// because they held off implementing <threads.h> and C11 support for so
|
// because they held off implementing <threads.h> and C11 support for so
|
||||||
@@ -52,9 +56,9 @@ when ODIN_OS == "windows" {
|
|||||||
@(link_name="_Mtx_unlock") mtx_unlock :: proc(mtx: ^mtx_t) -> int ---;
|
@(link_name="_Mtx_unlock") mtx_unlock :: proc(mtx: ^mtx_t) -> int ---;
|
||||||
|
|
||||||
// 7.26.5 Thread functions
|
// 7.26.5 Thread functions
|
||||||
@(link_name="_Thrd_create") thrd_create :: proc(thr: ^thr_t, func: thrd_start_t, arg: rawptr) -> int ---;
|
@(link_name="_Thrd_create") thrd_create :: proc(thr: ^thrd_t, func: thrd_start_t, arg: rawptr) -> int ---;
|
||||||
@(link_name="_Thrd_current") thrd_current :: proc() -> thrd_t ---;
|
@(link_name="_Thrd_current") thrd_current :: proc() -> thrd_t ---;
|
||||||
@(link_name="_Thrd_detach") thrd_detach :: proc(thr: thr_t) -> int ---;
|
@(link_name="_Thrd_detach") thrd_detach :: proc(thr: thrd_t) -> int ---;
|
||||||
@(link_name="_Thrd_equal") thrd_equal :: proc(lhs, rhs: thrd_t) -> int ---;
|
@(link_name="_Thrd_equal") thrd_equal :: proc(lhs, rhs: thrd_t) -> int ---;
|
||||||
@(link_name="_Thrd_exit") thrd_exit :: proc(res: int) -> ! ---;
|
@(link_name="_Thrd_exit") thrd_exit :: proc(res: int) -> ! ---;
|
||||||
@(link_name="_Thrd_join") thrd_join :: proc(thr: thrd_t, res: ^int) -> int ---;
|
@(link_name="_Thrd_join") thrd_join :: proc(thr: thrd_t, res: ^int) -> int ---;
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.27 Date and time
|
// 7.27 Date and time
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
// We enforce 64-bit time_t and timespec as there is no reason to use 32-bit as
|
||||||
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
// we approach the 2038 problem. Windows has defaulted to this since VC8 (2005).
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.28 Unicode utilities
|
// 7.28 Unicode utilities
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.29 Extended multibyte and wide character utilities
|
// 7.29 Extended multibyte and wide character utilities
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
@(default_calling_convention="c")
|
@(default_calling_convention="c")
|
||||||
foreign libc {
|
foreign libc {
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ package libc
|
|||||||
|
|
||||||
// 7.30 Wide character classification and mapping utilities
|
// 7.30 Wide character classification and mapping utilities
|
||||||
|
|
||||||
foreign import libc "system:c"
|
when ODIN_OS == "windows" {
|
||||||
|
foreign import libc "system:libucrt.lib"
|
||||||
|
} else {
|
||||||
|
foreign import libc "system:c"
|
||||||
|
}
|
||||||
|
|
||||||
when ODIN_OS == "windows" {
|
when ODIN_OS == "windows" {
|
||||||
wctrans_t :: distinct wchar_t;
|
wctrans_t :: distinct wchar_t;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
@echo off
|
@echo off
|
||||||
odin run . -vet -o:size
|
:odin run . -vet
|
||||||
: -o:size
|
|
||||||
:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check -define:MATH_BIG_EXE=false && python test.py -fast-tests
|
set TEST_ARGS=-fast-tests
|
||||||
:odin build . -build-mode:shared -show-timings -o:size -no-bounds-check -define:MATH_BIG_EXE=false && python test.py -fast-tests
|
:odin build . -build-mode:shared -show-timings -o:minimal -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
|
||||||
:odin build . -build-mode:shared -show-timings -o:size -define:MATH_BIG_EXE=false && python test.py -fast-tests
|
odin build . -build-mode:shared -show-timings -o:size -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
|
||||||
:odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check -define:MATH_BIG_EXE=false && python test.py
|
:odin build . -build-mode:shared -show-timings -o:size -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
|
||||||
: -fast-tests
|
:odin build . -build-mode:shared -show-timings -o:speed -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
|
||||||
:odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests
|
:odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests %TEST_ARGS%
|
||||||
@@ -202,38 +202,9 @@ int_to_byte_little :: proc(v: ^Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FAC_6_102 := "289BE8D277AAFBEEE05072D73DAB0CB188DD578EEF398C7BE4AD105965CC224F04EFA7E0D5267C117B276A336BCBFB948A4ECC691FAD1BC06265385D9D75404AED9F52A5DE6C29085D0656DE4D8B26A303E8B97D68C32648DAF1BECC073A7AC7B08145B0790E323682AB5A4A7D08134F92317C9A66C6EC3F8D389B72AC2270FE3F39E3C582F7C258A95CAED677313A7D9B167D212D3D3501A275EF11A215C1AA7B2D9793801C9C71AE5D07F1A43403F3BC573FAB54B69ABFF16138AA17661C5F41D3BEA2822523C89294F93C4A85B760DF6ABC27D46EA7ADCEC61BE13B8F57420F225CCAFF32DE2B2C2BC5C43000A93E770A148FED76886C79449D692C980C64DB590B754C845B31FD6A0011815B701541402A56F9A7140FB371470FDF167FCEB3DF30DA38B01A979CEB78034F62B82E23A3595D6B4893EF32E70969BE26EF36D66FB6EC2F051C7BC74E842964DC5CA0FB15457939B89E9E90108D0F0D8FF1BA87FE566170B32F2AE241C85A782AAE27602F709B46F55B0FFF9378CF0BE763079CEEF09422B8F67D897CAB87887712E42FEA9B743DC72E78D24F73BBBAD146F47078625FE108929A401A69D35BB0419B54283C274F04B683720B88D7158B9EFFA3D26321C94FD70E4F0BB2A847EBC0A77CDFAB3C66A1A4C022B6354FFFF7D8A279F63531DD2BAA32233ACD3109AF489A8596B19F5CC2FFA1BB49D6BC806C6B9880BFA80E01A3CE43053238E23D9C88A8DD184BF3B99C366F76DE0E0276F389C07F67DCA36045CCDC73E6FE8E6BE8679E351547AC7E4D4FA24B92F0870BB3D7E777F65E5230D6DD640118F7ED471A929511684147BB97487BF8BB4621C63D0B7A3BC9C5BE316118B269F2C4BE996D173C1740CC43C276758B3BA5991149D6DCD76910359F7FE0459C8D255A0CF6982831FE3CAC9D7DA4C074C5FCAB1631AE2878C4CDDF667F8DFB4D81A1D7C2B578A44BB791EAE14BB380098F971A0BA27941392804F8741BE28EA56CC4024BB48033376B8223DFEF075B6DEC2B2602CBCAAFB9C72FDF7933FC8BC48B1AEBAEEDBF3621F0004911015EC4DD4BCFB6F9708A293E12C39B2EDF93B613089AF1C4F4A812B9CCAF57C2CEDAC637D2688426D6145FDC2CEECC589F2E75AB560F1BC991DF28785440E00BA9FA8CE5CEAB43AF753BDE88FA9770857CDFDCF1E2CC6A02D4860B67F40F9FA6B4E0F3EB8C17A4843569595156450519B011826826642D9AC43575914BB45F5A5C24914BFC9AC620AC067E8603BC56E6B3B863F5C29393CBBF6AA72D6367FB47EE996890BEF7D057BBAB0E54203B0147CE2BD3105A322408ADFF5BC3FB1ED90E3B14CAD6DD25E18AD358577A7B58FA19AB6F83F5CC8A2C19E9E5CFC189C727F7920C1A059537110EA2A7CF27D4F9A046FC8C43291CE67BEB48FF589CA191AC132B05E54DE0D019B39F9C792BCF9053CE2403901BF660E9EA681C8A2DDD014F2B024D6206405EFEC8D9DEBB9EDC31B49AEC6AAF76FFC5CB130AEFB3125CBAD951E6A67534F7658330F62D28D8BE3B1D7B5290B55198129B8BD8E01FC4070EBC567A33D7693269AC7BE77CB44FD2E2D8DE2C04129FA690094131360026EDC3FBF658B3569BBF373C5DA19C7AD20A31757ACEFDB042BEC0EAE31ADA3346028854D81F6B7B7C7B44F2B97CAE1894F564AA29648DBEDCE0898F6C3F6B0800ECD4C92F659E659FC6D5B248FAF627DA467232C1A890AC21212471ACF307514593CF74516F130C9ACB435992385BC6E41AFDE84DFC2CEFE28DDA482E358BB65FC9A289D7315E399B044DB81B4719D5687E876DE41C5AAE28DF0539D61BAD53A57066EF621BFD6E373DD1DD86FA167A731982A5E84A898CC5A7A9FBB91753FF5DB62113DF6A6245AF72198D6059BB75F4F63892D40A2A1C78EA3B4949E8AE7BF344A8E2A3964E9701C3B66C4989A1090107388B6A29736C90DE652C924CC6C055DAABD2CACEE145A4F7772442BBFF938AC4D5F6266AC7301D36E9E87074CBC0651ADD7EE5D795E8956E512CC63D81731D5B7FCFCCBAD254EBDDBF26ADA68FFBC8D46481512B4964ECFEE1693C4AFB7505FC60267E0C5D613C89D210AFE1BE718DA5506424A5D9D1035A4A68F8D24084FC650E9D88BD111DA838A24E15E38B5417D9B108EA1D597418D1B659EDC4C9E3FD8E7FA10C5F1D97252A3BE3FC3991CB8E88DBF0BC2E5612B36152B67B9C906BC5179712DBDFBB10ADB6B3B7E946D9D2F224F80AB01DBB558959CEB8C1A5549F8FDB10CA2B6F0A267EE317B9E02ABE9B628A2B592D5C63794E98F6E1943DD9A644D136007BF5D1CC91A7F2D7E1BB7BCECDCB17A1ABA3050133B8218C76664D2EDD1714206C7A31FD943E0E03D37222733E575D8BBB24743FF59D727C43DE4F7A5F311A4AAED1DB314D11D10212B61005817B016BBAB1118EDF434ED7C9C8B6B009AAA89CC21614D24A21DCC03C59B6EF06A6653EB55168FE3589B6808BFCB86C91453377C6D7691C364936A53C15F6B8169B2A033E37E7F07D68C2DAFB661B0A1A9102B46B46CFA5D4958FF569C5F11F6859893FF972B171A01AB93ACBEE832E300F88C5383D818F0A4F4C084331050EFB23F151F2C4FCC06816599597DC7BABFDC1C04EBBB06F3920BF45FF0B7C317EA51A41715FB8AE2ADAA6330DB6E268106575FC388D50BD8651D2FFF4E4151D529727C4F29D3E6A460230B55B5B020B87F2A3F710F16078AFEEAA34652645BDD24231A36B461A7657978522C1CBB0D68CB1323C8ECEEE07720A95529EB4562653EED6DC3AB55439F38A9C3079F7B6A2AE807C70E5637C5C0E2CAE92F5CDAF4A14692892A4E7006A4EC7D754E710C9AF72A248CB02EE69A7AB2527322CE9ACE1BC717B268B342C601C0A45DD5AADFF326980657B40B97DA832F3B79260E4BECF5F88EBB2E23514B1A84B785E80730FADAAA412529D5E64D32B20F72BED8F2FA78771E5B754A2BA8D6BC9FD98A9DDF48A5AABD00BECD6E9549F0E0AD51854B701A3AB40D77BDDF3A2833FE1ABE1420AE663AAFEED794E32F16E005257C41EDF95CAF818248DF8BBD952D12DE6DF3E7FFCAC8F5C57B633E6EA702BA29C468CD4BF289FF051EDA4253FECD2AC47EC1E4B1FF3FE72D7DBBEC435E72CA521E75CC101F0FE4A687FFDEA4ACF3405DAFD84692312BFDC238E2FA73388E3068F7D5A31F30A736AA882833DDA7784B036A169716764BBA18234082AD9B5499592242EEA92A78F4C1BC73FDF8FB66AC80E59E6434F2D024F3B9833DAC1473A3F4EE1DF2753B0EF44D47907C9EC5FE321A2317A9DF937ACB705480AC0512900AB4D64679F41324F35BB2DB7714B57926E7D5CCC391B90DC5B300C075214741252A48CF45BD18E82C4187A87F95B766C966E4052030B1F6436B028566B2A020E36988D37BE8579E87771B9C47336319F8FA3276B9C67649E61B65BBA76D22DF87CCDF91E6FA28449AF25D4F88F1A4C9C69C1F75CB49FAA133B8687213FEB8C9C308D8DD997E257483EEC23CE61A1C273F006F2CDALine truncated
|
|
||||||
|
|
||||||
AA := "7e1c0f3c530239c47c1c5e891032dba5bd96e8d1fa32270e69640b3b6da7c8adb96839d072a163855b28ae60cbafef459add4ac7cc4c5111e851f154249f7409837867bf3d2574a0495be80a9c9d305f7f5bc7802d2c104ed297234e672a1f69eef05d8c28d04afc0d1b77afa2bfb09905631688fcaa5d5930e5b24f01e8515f8dced9953b94306b6066911868df6fa668ad3aeb49d3a53e93e0b90de64a27f1d5eea7e21fc71b7d3b4ca92798163a32b6df83e760a826fc71666e5301a4a14ee7fdb995a343b1d98a3bbce96261c2c923f1d0d2d1c16eefc5289daa6e7c116377e0801eb9dd407b490a76dd5b7980243a5a48915037d2df32f8ff356cfd7130390a71a2b37a4ca89515718db7593a4585d0901b7e84d39f8af4b9af071f441d1653b42e2e397c9c83f667041c94c8cf35b57e2d2c6f5293935da575bacd899ea1832560802d7f4b1b06cf55b2e06151a6eb0fad2dfe53d081b652257c75e07816fca1e8bdae54a8e33eaae327e659f376b0f27c8958eb8920c12318f4646ac529cdabeafa08ddd403a06d50918efa34701de6a74d2623d3492214feb10a88822bbaad699a4c3cdd14e1f5c0996ce7b4f5ecf98d919af3715e4ee12da37a883b4568ab69c61614e04bc649ce0f176773907c4af26324f78ad39639cb97fbfbc27f972fe4f2d78418d3c9313ba0157db3838bfee7e6771a682bf61bf15d440da9f1d16a79638460ab080b425fc1505d08213c12f47d925f7a00d1fc05fd2f4b834f35c3e933d24dd1d5167823cff1d04101bb376b5950073b0e4d4d6f76d9a6118792ad071775e507d224d032314704f1f7fe73b26e7c6ff2de5989900080cba339028a854536f024bd03e3b01f64b105c073a89952eae97a49140fa52018b8069100727ec01c3a35aa3fe96f4ea012fe1d840e205a75e109afb84fb70663629dd6d133e0ed86f7ea27c5d49842e98edc13a0c795ab98baeb2fa4ce1fb3c66261ad1d702f9ade91905a0fbdd5fed483e019a7858fa88a17204b55cdb6ee89ed62ed1c2805a6d0fd1e761d934e13357726e088fb9875c3fa44b344408fca5086114bbf94a719bdf50a65da1a583bb8402242eca51161d40ae64ad6b166f538362402b13cb5f6c80e24c8cf1155fdd4a574d1693c79900acdb4a298b2a51a33e60cf1bcd18e937feb91c8891decfa2895d2be776cee2dbb563a3fa026b26aa374ca2b3baf53df4d8e3895af5990f7d40abb5d9085c4e9cbafb26b4c575f6ce908ca7597e1a03e10f161ced3a4e1e9028328efac38d893960b36c7a7de09f970b098ea37710878d6467f2d649067ac263ec249f7bd8b8ed51e4fe44bdcd390de9d657c176120f603f9610e990e8bb3a8a12172124a4a06014c9823b95dbb6c2d29633e01428d8c6050b357dff2d37afdf49cc717665621bc91c77fd3074daa3e086dfdd159476fcc03a07c18f325ea0bedafc038af9efc346ea859196438cf9e5f2a944664483e096dec37bfc6537c72d4415439e721e9714e07ff5efc3c4ed8be1903464fa4540a7ccbcad2e3da1ffc4fdb54f7f810371995c16cc8e7722b03bff16ad3e9a7c82b0f9ca2d83ea81543a46e169bb7583cdf5938e85c8d7566824ebd8041ae7063538ee973d37e3da7315bb7d33eb9b9877af3e7f35999ce91a6fbbf28d31bdb05cc478326961913f3473fc2c3838848befabe769ec5046ea3dbf6a4e58a197541f1eabca0337173dca38085505b53607625467cc138ee58cd92559637d71e62a264ccfc97332f549f12d80347740eee5e9daf06867393d25ac370419fb40d8723fbb9c4f55147fad61d935f0e937b4f38d4896c2195fd097b0845077f74b098cde29037ea7e92e28be175bffd399d8563108a9005c219a88b1c366936654da39849e9169a3269ae0ffd80d74757e3b8b7f0b85c48470920dd4323a5dce5d2ea484e9220b5ea3c2993d48a9fcef4991a47d50fbb75628a9de22271301d726c8d47857e9cb2a040c329863809b0b3f0bbf8f891516826aa763616650005d361ed51148fa212369140988c3aa01cb16f211c96bbb75bd2981ce7cc081efef0eadf56a0e4e047dea1a07a762a1375bdc4704b30f18c2ec044123c1b3754084da3ff62d90ee61b4cc453151e2072b46264f385ae1b485f1573c27b800e3804f06c9dd7595dfd1423c4fe0cf0bca2a2eb570a78c66985efc3d2113e9cc28ae6f94247bcc2c6e7d4c18752ec7a9532da166d50329d8bbc1c798196c30d9825fae53fad34d4e7f20d1ef3cba84376b56f5a063cd91fa9f17a059b452e028c68ad14990e15466e2dfa0034bf3c6162e9cf5ae88c72be95e789f9a12ec545c4010cdfc8bca57c9ac927b729af2fd7ec1e11f3b693cdf7b734df393283aa19d815416e77259fab3269505a322814da13c7055e12d6bfaa1ad29a17d94039bd167cbf04cb49d8b6d799e192c65a4d25fe223e550da47e8af95ae2f3250502cf17249c3c3c1455542a95faed7bf9fc71b1b077957c9aea1eee229b5c4012dc23aee8ee6b6008b9c416120f72d48ac8e79837ea21adc5cea6e43112ce3910f80097130cb8ee076a06d800e4c2ae73ca8904549046f595a9f1471eb54c89b1a0850292978fd9eab9056feb945b5cc04c8534d94c3a5a331f7dedd096aa6b211fed44105fd7409d05e729040b9f67d88579046ad1a36e9314aed9c91faf9755abb2bf2b8df9ff0553e41433bcc5f3d724d50fb60dc7f712e765d497296fa5edb0b432563afa4621e2863a57bb8f772d3284d9a985b0c650fcb60617fb93117d15a1209ced94d031094195fa94ab32d66a2c750e14273e6a62c93e4bd7a06670ce4fc819a08246a788c47ba379108c05d26e60113b9f0f9440a531a4ba6cfc3c9b8564bf8bd1f4e3cd00e2c19f8f935e2a921bfab0c15e49a172a28e2ddae40b30a0caefe475174b245aa27ca162e50a8cd2d7fdf5dedca0d2d812ddd50950250aaf9a4475d9ae9b9c85970305e3959ceef8f9b131b22d4c1e291b39e82d5acbc0e63569a15187cada04d43f9a2c194285e2d992c0de5ad6fa01d726f8e1b684de19b2409b5f9f028d6f915afff0b5f2a40f0ebc3ede023058575ffb33dc5be1ed2b4e477f566345246f59596738c2c082c53ffb59bd3a9c684f2e5a465a7cd8827a54de7f17631d57d41c62833a796649e61188b217265eeebbeb5c2d86d27f52924d708515bf00aa4a6c42429f7d7949faff15eb23c75ed8525f812be080afff85c113437e94cb346cbdef8b8a008982659334e04a64e471fb9ee779f5f9a4904ba7bdeb9468764b3afd6539c5d6604cf6ad6846367e6f36623d75bc0b1316b92c36c284d8f80113e60c7ff1e87f2fec0fc64a354f5b53a01acac64304794d393ccd2c8c652ad13f0937a1123572ca3538a1a36cb470a73c533d4c519c139cc1ee49d0c7b43af7514ceab5ee0a1d14b1ffc03bfcf53b8aeb9eac66ef62ef14d002a78b1242e40ffa6d3600678ecb5f61380f0c67a6dc4fbc2f91381b75c60fb7e17d78Line truncated
|
|
||||||
BB := "2937beb399926019948796c29595aa37cfbddc2ccdd8fb9ae367f45943210393e7e0e5bcbda767fef76d3691d26708fa8e10452ce5d4fc98bd19c0104100a12cd992864e875d3d521cd3d9713dbd5db86b2a94faa7ec7ea92e761967fb89ab9a0ea2561d4c42f747d1d52d3ca3d63359b4d7ebc2db1841546df87f99078232928bee89c028cd92444022811a81ec6c95e168b6c2e94a37f3a59bb5891d6e7e6a85b57addc4aae712e527a5a2735b11513929d67471ca5104508e219610e1fd2c363b98a3b6786d5b84c6e57eabed5a4e91f4b4ae24edf57afb792f85090eb0985bb1c53e3b0efe41f0c78a82aa150d2bca685cb30bbb2aef495afe455135c378d48f8fe360670d2e9e186fd3c55eee0f9dc23a9cbaf4dc887a6e3765850b8d95360ea3ebc72ec57382331f0339a57ddc82a97350bc4d1351debd63c38b0b1240d7a8e0fd75a302a40ddda27a8c6dbb18d5e76fef1118807bc5b5f9a19d96e789cc0e26da0987fdbee7ab544f1f742b741bc5d4640496e562dfbf198fd8a2c5d8fd8b6a22cdabea362b1cead3d0eba56ae8462b30c2c9b40612722c3887fda1ab8ed8c5b1439b0a8bea536bc9b2dbdab2dc91f20bd1a71709e19f2f7f7b70cfbc0a9fb1d12b1fabc3787abd687e1c2573b2340dff3660c7b6abfeb082b852b4b4cc5aee178392693a4ca829c8b5bddbe57b972c357c268d3eaed55e0c6e913aefece764b03e015cf150ab3815c9b6ec51df0a9a95c32155f3044007c35e64a47292364a96b998c044467fbe63e5628d3b1f21c57ecc32578dd50ad926376a916c8378d1f33e0e9bcb3caae70c08c44aab747920eb2f7a84eb1842ab8453d0488aec38a5a62b711f9895a8089465275820679bcba2d3c0b71a0d17f13a46ee630f56a987683032562919a750df84395294c34737a34d9c3f87f73f68d0d73d6eb4d7683bddf901100db696b38a677987f746d09ca5a59988df9a3423604e4a892501b4669bdcab7304a374194099fa4a43ce381d21240aaa08b6c29a8a3b94725051a4ac430bcf3f1d6238e33a59a83789cf5d68aa5f001a72bb15b3a08925081af9105b01c2233bde416dbeda5ff88e14f164cf1d6bde98624da2be67f8e1166dd7f9982a3a525b7bcc95b8d7a3635e84e2e080b59694d89ce5f8e4329560586f31a9d7922b9bec0efe2843a7a0780f0e7482dfe432edc0cc2470f1f9f95cf833fe7678ba06e92eefba64675a5da590898c95568a934295ebd04ff73382c7ab24661eacb98d32a6e194101d127dbc92e5a83aa39e5a6e5fa3af10521f148b9f53308b019cbbb379c0de0a82042dc5d2c016c716cc305c3c602c2aea99cc50d26d480376630616d06687f329b0ea0106f02381ef74efae778e71a9ec87a6c195a06c08268ac0739bcdf05bc1a233aa9878b110e1903eff8a53a54cede923d98d1fa75f1e69c19f414486645b96932cfb8145b344ad243038c1c42a348695a2831cbd6585fd31189a24fa615b19e226f4ea143d00b4bbd8e56e4fa7eb5f09270f1283a4b808fa7d3ee3da7eedc3bd6cf15303a15bc1240b0c07c0e34b88c563463ec9c64ee11a887d3e8bc1a0c2cc3680f19fe534a41fe1cf822599e8e6ab128e17f3bae77fbbc746298d8f3677afba82d1ef7e978d785a2d84f96c3fbe00011542e07a9062076233116c662430520bcef5bdb5cc9139b1f01f32d57e9ddcfd27e98a630b5f9e980172370fc4d064649fff411a2d913e75aef9101edb709ce091d6e973b033de3787c504967eccec22bc37ec43afb01f50a655040f14b2832c895990e81c94d546f3a350b8a109eeeddc714ea6c4de00e9102b8d1eb69e3b4c2ab28006d144baaf78ea13ca1bbad46bad5d3bcea7f8c99645fb33cbc554c053a75a2a2014fac095975a2215cc40472a6f5d6de6618e6eb05eb8b97ee1aab6425219bc6249f0f327fb6f33879ba1d4e3feffa67ac26aa857dd924f4f91cb76bd724b70a0a3dbf57b94484f678c2e2582ae69f3d219a0e2fa5f3cd1124cc0b2cb7ba928921277989d4e416ca617f53e5e9e215d5472526915d822bfefacc6d6102aa4b53655aad0eb7690d2f795b16fe45715aaf5825b7cda38b8c12f234538318e042c48542ac18456a37a6988d3e030bbbfe634c7df9dd50bf526b9762e86ddbf5fadc0a7be4a5a929006fd71bbe353e6054976146df7c713e1239f5c79d23ac33a1ace757d8a65a909fdc79791ce9d13ecd17e7533a7deb8928749b07b7a3e07c2684e01081da33337d8f6fc477cc36ff46063626370b747c72acf11510f911c8d8623c7dd4d96243e4e5088657f49fbedf3300b07bcc4334e7197dce79b79241c42fa12007817e80b2b8cd2c8e802372ad1f167400ac69bc2fc8a58bb689dcc66dd642d0dfd0f2f84c372157563fac3a98fcdd1acc7b569d8da11c95e5d94cac5c5d01b0333ca2171af2b12a341e71e4d2ab721b54ac981d9c69cfee5691c2f7177e4a3cef997d98b01fe3eac117f671c0e92b810070400bec1f24a283c2da70fb9b505aa22463c90736017dd670e60ae711d1158fe2e571621d35e5004657ef29eab35c716dda196d7715a6a933f8e4e52e43fe154f685540bae72c23befef55f1b72ba4f8634e09a66184f4ffedc5d72e60f1843200cb178e05bd1ee01d9637adcedc2dbd98a9100ff807dfdfa0ba7595ae27562476f17eec6c70a5438ada39ac0fdcf882a212cac3ebabfda6f478c3d834bac8c8e458c7fbfb212f19245869b5258f3e5149cc0559ae57d24f78fa31dbb613b9e1d986187ea3dc876139d8fe08ad823d0ff55d3bddefd91929432147563d9c410197d536e2bc925157439921eb6ca8e3cc8c7717b5a2852b980d8e1e6db7ed88f7b3a920ff9b8022aa4b190b32aaab2b84813ed49a06d3f253abefd9710de64ffdf56d9dea2c040ed850a5e59e542059bdfb9a41044fc5e9866cdba0f62a52535f7db238f4635b00be08d9ee6e3f37d9d28bdc3f2e07bc5d6299e04181cb811e7d05fa2b9c49f43b764161a73f3a61901f5a934802e3e1a58dad63711e986334762d38ee2cdaf5540e4af66ac60df2e74ef922a687c730e0e5ef4e9a683918d41feba17f53bbae933ac9e7ac7f69069f8d23af32d3f0f54771febbfb70efe0ff7076258b4d5f90c12da20f3969b140b1367f3d09d3e934c43641a423b73773a1d6ab32bdb32003433db68fa35498bdd33b450dc88e44c955355e1c219dfd9324180dcdca07455dc43a6da573f9fa5028d3f9459e3a6e10b0de3014b8936c081c1b620293ab9760e7ff3019ab263d8df1a149e64088abb0b4c96d6f7188231afc37b1348fd55127d612e4cfbc01453fc38bf2db85b1f13884352e860d28e98d55762e87eb1ed4fd3f9be45c3f2f9d465d094e4ade75c2e3a88f555414c68eadff600aa0dbaac9c9e85755dfcb8ade4e713ac45a2733d5a78ca96b4338b65fc43503dd8189b9ecc8622e3ac01dbc761c3b24e9769dff069799f1b65e80cac2b19213bb52c6a1b1c04fe06f3651Line truncated
|
|
||||||
|
|
||||||
demo :: proc() {
|
demo :: proc() {
|
||||||
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
a, b, c, d, e, f := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(a, b, c, d, e, f);
|
defer destroy(a, b, c, d, e, f);
|
||||||
|
|
||||||
atoi(a, AA, 16);
|
|
||||||
atoi(b, BB, 16);
|
|
||||||
|
|
||||||
_private_int_mul(c, a, b, a.used + b.used + 1);
|
|
||||||
_private_int_mul_toom(d, a, b);
|
|
||||||
// _private_int_mul_karatsuba(e, a, b);
|
|
||||||
|
|
||||||
fmt.println();
|
|
||||||
|
|
||||||
if internal_cmp_mag(c, d) == 0 {
|
|
||||||
fmt.println("Toom is correct.");
|
|
||||||
} else {
|
|
||||||
fmt.println("Toom is not correct.");
|
|
||||||
}
|
|
||||||
|
|
||||||
atoi(e, FAC_6_102, 16);
|
|
||||||
factorial(f, 6_102);
|
|
||||||
|
|
||||||
if internal_cmp_mag(e, f) == 0 {
|
|
||||||
fmt.println("factorial(6_102) is correct.");
|
|
||||||
} else {
|
|
||||||
fmt.println("factorial(6_102) is not correct.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
|||||||
+92
-29
@@ -659,8 +659,7 @@ internal_int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.alloc
|
|||||||
Can we use the balance method? Check sizes.
|
Can we use the balance method? Check sizes.
|
||||||
* The smaller one needs to be larger than the Karatsuba cut-off.
|
* The smaller one needs to be larger than the Karatsuba cut-off.
|
||||||
* The bigger one needs to be at least about one `_MUL_KARATSUBA_CUTOFF` bigger
|
* The bigger one needs to be at least about one `_MUL_KARATSUBA_CUTOFF` bigger
|
||||||
* to make some sense, but it depends on architecture, OS, position of the
|
* to make some sense, but it depends on architecture, OS, position of the stars... so YMMV.
|
||||||
* stars... so YMMV.
|
|
||||||
* Using it to cut the input into slices small enough for _mul_comba
|
* Using it to cut the input into slices small enough for _mul_comba
|
||||||
* was actually slower on the author's machine, but YMMV.
|
* was actually slower on the author's machine, but YMMV.
|
||||||
*/
|
*/
|
||||||
@@ -669,13 +668,11 @@ internal_int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.alloc
|
|||||||
max_used := max(src.used, multiplier.used);
|
max_used := max(src.used, multiplier.used);
|
||||||
digits := src.used + multiplier.used + 1;
|
digits := src.used + multiplier.used + 1;
|
||||||
|
|
||||||
if false && min_used >= MUL_KARATSUBA_CUTOFF &&
|
if min_used >= MUL_KARATSUBA_CUTOFF && (max_used / 2) >= MUL_KARATSUBA_CUTOFF && max_used >= (2 * min_used) {
|
||||||
max_used / 2 >= MUL_KARATSUBA_CUTOFF &&
|
|
||||||
/*
|
/*
|
||||||
Not much effect was observed below a ratio of 1:2, but again: YMMV.
|
Not much effect was observed below a ratio of 1:2, but again: YMMV.
|
||||||
*/
|
*/
|
||||||
max_used >= 2 * min_used {
|
err = _private_int_mul_balance(dest, src, multiplier);
|
||||||
// err = s_mp_mul_balance(a,b,c);
|
|
||||||
} else if min_used >= MUL_TOOM_CUTOFF {
|
} else if min_used >= MUL_TOOM_CUTOFF {
|
||||||
/*
|
/*
|
||||||
Toom path commented out until it no longer fails Factorial 10k or 100k,
|
Toom path commented out until it no longer fails Factorial 10k or 100k,
|
||||||
@@ -861,7 +858,12 @@ internal_int_mod :: proc(remainder, numerator, denominator: ^Int, allocator := c
|
|||||||
|
|
||||||
return #force_inline internal_add(remainder, remainder, numerator, allocator);
|
return #force_inline internal_add(remainder, remainder, numerator, allocator);
|
||||||
}
|
}
|
||||||
internal_mod :: proc{ internal_int_mod, };
|
|
||||||
|
internal_int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator := context.allocator) -> (remainder: DIGIT, err: Error) {
|
||||||
|
return internal_int_divmod_digit(nil, numerator, denominator, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_mod :: proc{ internal_int_mod, internal_int_mod_digit};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
remainder = (number + addend) % modulus.
|
remainder = (number + addend) % modulus.
|
||||||
@@ -909,7 +911,7 @@ internal_int_factorial :: proc(res: ^Int, n: int, allocator := context.allocator
|
|||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
if n >= FACTORIAL_BINARY_SPLIT_CUTOFF {
|
if n >= FACTORIAL_BINARY_SPLIT_CUTOFF {
|
||||||
return #force_inline _private_int_factorial_binary_split(res, n);
|
return _private_int_factorial_binary_split(res, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
i := len(_factorial_table);
|
i := len(_factorial_table);
|
||||||
@@ -1106,10 +1108,10 @@ internal_compare :: proc { internal_int_compare, internal_int_compare_digit, };
|
|||||||
internal_cmp :: internal_compare;
|
internal_cmp :: internal_compare;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compare an `Int` to an unsigned number upto `DIGIT & _MASK`.
|
Compare an `Int` to an unsigned number upto `DIGIT & _MASK`.
|
||||||
Returns -1 if `a` < `b`, 0 if `a` == `b` and 1 if `b` > `a`.
|
Returns -1 if `a` < `b`, 0 if `a` == `b` and 1 if `b` > `a`.
|
||||||
|
|
||||||
Expects: `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`.
|
Expects: `a` and `b` both to be valid `Int`s, i.e. initialized and not `nil`.
|
||||||
*/
|
*/
|
||||||
internal_int_compare_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (comparison: int) {
|
internal_int_compare_digit :: #force_inline proc(a: ^Int, b: DIGIT) -> (comparison: int) {
|
||||||
a_is_negative := #force_inline internal_is_negative(a);
|
a_is_negative := #force_inline internal_is_negative(a);
|
||||||
@@ -1165,11 +1167,72 @@ internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
internal_compare_magnitude :: proc { internal_int_compare_magnitude, };
|
internal_compare_magnitude :: proc { internal_int_compare_magnitude, };
|
||||||
internal_cmp_mag :: internal_compare_magnitude;
|
internal_cmp_mag :: internal_compare_magnitude;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if remainders are possible squares - fast exclude non-squares.
|
||||||
|
|
||||||
|
Returns `true` if `a` is a square, `false` if not.
|
||||||
|
Assumes `a` not to be `nil` and to have been initialized.
|
||||||
|
*/
|
||||||
|
internal_int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (square: bool, err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Default to Non-square :)
|
||||||
|
*/
|
||||||
|
square = false;
|
||||||
|
|
||||||
|
if internal_is_negative(a) { return; }
|
||||||
|
if internal_is_zero(a) { return; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
First check mod 128 (suppose that _DIGIT_BITS is at least 7).
|
||||||
|
*/
|
||||||
|
if _private_int_rem_128[127 & a.digit[0]] == 1 { return; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Next check mod 105 (3*5*7).
|
||||||
|
*/
|
||||||
|
c: DIGIT;
|
||||||
|
c, err = internal_mod(a, 105);
|
||||||
|
if _private_int_rem_105[c] == 1 { return; }
|
||||||
|
|
||||||
|
t := &Int{};
|
||||||
|
defer destroy(t);
|
||||||
|
|
||||||
|
set(t, 11 * 13 * 17 * 19 * 23 * 29 * 31) or_return;
|
||||||
|
internal_mod(t, a, t) or_return;
|
||||||
|
|
||||||
|
r: u64;
|
||||||
|
r, err = internal_int_get(t, u64);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check for other prime modules, note it's not an ERROR but we must
|
||||||
|
free "t" so the easiest way is to goto LBL_ERR. We know that err
|
||||||
|
is already equal to MP_OKAY from the mp_mod call
|
||||||
|
*/
|
||||||
|
if (1 << (r % 11) & 0x5C4) != 0 { return; }
|
||||||
|
if (1 << (r % 13) & 0x9E4) != 0 { return; }
|
||||||
|
if (1 << (r % 17) & 0x5CE8) != 0 { return; }
|
||||||
|
if (1 << (r % 19) & 0x4F50C) != 0 { return; }
|
||||||
|
if (1 << (r % 23) & 0x7ACCA0) != 0 { return; }
|
||||||
|
if (1 << (r % 29) & 0xC2EDD0C) != 0 { return; }
|
||||||
|
if (1 << (r % 31) & 0x6DE2B848) != 0 { return; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Final check - is sqr(sqrt(arg)) == arg?
|
||||||
|
*/
|
||||||
|
sqrt(t, a) or_return;
|
||||||
|
sqr(t, t) or_return;
|
||||||
|
|
||||||
|
square = internal_cmp_mag(t, a) == 0;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
========================= Logs, powers and roots ============================
|
========================= Logs, powers and roots ============================
|
||||||
@@ -2300,12 +2363,12 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all
|
|||||||
/*
|
/*
|
||||||
Shift the current word and mix in the carry bits from the previous word.
|
Shift the current word and mix in the carry bits from the previous word.
|
||||||
*/
|
*/
|
||||||
quotient.digit[x] = (quotient.digit[x] >> uint(bits)) | (carry << shift);
|
quotient.digit[x] = (quotient.digit[x] >> uint(bits)) | (carry << shift);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update carry from forward carry.
|
Update carry from forward carry.
|
||||||
*/
|
*/
|
||||||
carry = fwd_carry;
|
carry = fwd_carry;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2331,17 +2394,17 @@ internal_int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context
|
|||||||
*/
|
*/
|
||||||
if digits > quotient.used { return internal_zero(quotient); }
|
if digits > quotient.used { return internal_zero(quotient); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Much like `int_shl_digit`, this is implemented using a sliding window,
|
Much like `int_shl_digit`, this is implemented using a sliding window,
|
||||||
except the window goes the other way around.
|
except the window goes the other way around.
|
||||||
|
|
||||||
b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
|
b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
|
||||||
/\ | ---->
|
/\ | ---->
|
||||||
\-------------------/ ---->
|
\-------------------/ ---->
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 {
|
#no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 {
|
||||||
quotient.digit[x] = quotient.digit[x + digits];
|
quotient.digit[x] = quotient.digit[x + digits];
|
||||||
}
|
}
|
||||||
quotient.used -= digits;
|
quotient.used -= digits;
|
||||||
internal_zero_unused(quotient);
|
internal_zero_unused(quotient);
|
||||||
@@ -2445,14 +2508,14 @@ internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context
|
|||||||
/*
|
/*
|
||||||
Much like `int_shr_digit`, this is implemented using a sliding window,
|
Much like `int_shr_digit`, this is implemented using a sliding window,
|
||||||
except the window goes the other way around.
|
except the window goes the other way around.
|
||||||
*/
|
*/
|
||||||
#no_bounds_check for x := quotient.used; x > 0; x -= 1 {
|
#no_bounds_check for x := quotient.used; x > 0; x -= 1 {
|
||||||
quotient.digit[x+digits-1] = quotient.digit[x-1];
|
quotient.digit[x+digits-1] = quotient.digit[x-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
quotient.used += digits;
|
quotient.used += digits;
|
||||||
mem.zero_slice(quotient.digit[:digits]);
|
mem.zero_slice(quotient.digit[:digits]);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
internal_shl_digit :: proc { internal_int_shl_digit, };
|
internal_shl_digit :: proc { internal_int_shl_digit, };
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,183 @@ int_prime_is_divisible :: proc(a: ^Int, allocator := context.allocator) -> (res:
|
|||||||
return false, nil;
|
return false, nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes xR**-1 == x (mod N) via Montgomery Reduction.
|
||||||
|
*/
|
||||||
|
internal_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
/*
|
||||||
|
Can the fast reduction [comba] method be used?
|
||||||
|
Note that unlike in mul, you're safely allowed *less* than the available columns [255 per default],
|
||||||
|
since carries are fixed up in the inner loop.
|
||||||
|
*/
|
||||||
|
digs := (n.used * 2) + 1;
|
||||||
|
if digs < _WARRAY && x.used <= _WARRAY && n.used < _MAX_COMBA {
|
||||||
|
return _private_montgomery_reduce_comba(x, n, rho);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Grow the input as required
|
||||||
|
*/
|
||||||
|
internal_grow(x, digs) or_return;
|
||||||
|
x.used = digs;
|
||||||
|
|
||||||
|
for ix := 0; ix < n.used; ix += 1 {
|
||||||
|
/*
|
||||||
|
`mu = ai * rho mod b`
|
||||||
|
The value of rho must be precalculated via `int_montgomery_setup()`,
|
||||||
|
such that it equals -1/n0 mod b this allows the following inner loop
|
||||||
|
to reduce the input one digit at a time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mu := DIGIT((_WORD(x.digit[ix]) * _WORD(rho)) & _WORD(_MASK));
|
||||||
|
|
||||||
|
/*
|
||||||
|
a = a + mu * m * b**i
|
||||||
|
Multiply and add in place.
|
||||||
|
*/
|
||||||
|
u := DIGIT(0);
|
||||||
|
iy := int(0);
|
||||||
|
for ; iy < n.used; iy += 1 {
|
||||||
|
/*
|
||||||
|
Compute product and sum.
|
||||||
|
*/
|
||||||
|
r := (_WORD(mu) * _WORD(n.digit[iy]) + _WORD(u) + _WORD(x.digit[ix + iy]));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get carry.
|
||||||
|
*/
|
||||||
|
u = DIGIT(r >> _DIGIT_BITS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fix digit.
|
||||||
|
*/
|
||||||
|
x.digit[ix + iy] = DIGIT(r & _WORD(_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
At this point the ix'th digit of x should be zero.
|
||||||
|
Propagate carries upwards as required.
|
||||||
|
*/
|
||||||
|
for u != 0 {
|
||||||
|
x.digit[ix + iy] += u;
|
||||||
|
u = x.digit[ix + iy] >> _DIGIT_BITS;
|
||||||
|
x.digit[ix + iy] &= _MASK;
|
||||||
|
iy += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
At this point the n.used'th least significant digits of x are all zero,
|
||||||
|
which means we can shift x to the right by n.used digits and the
|
||||||
|
residue is unchanged.
|
||||||
|
|
||||||
|
x = x/b**n.used.
|
||||||
|
*/
|
||||||
|
internal_clamp(x);
|
||||||
|
internal_shr_digit(x, n.used);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if x >= n then x = x - n
|
||||||
|
*/
|
||||||
|
if internal_cmp_mag(x, n) != -1 {
|
||||||
|
return internal_sub(x, x, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||||
|
assert_if_nil(x, n);
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
internal_clear_if_uninitialized(x, n) or_return;
|
||||||
|
|
||||||
|
return #force_inline internal_int_montgomery_reduce(x, n, rho);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shifts with subtractions when the result is greater than b.
|
||||||
|
|
||||||
|
The method is slightly modified to shift B unconditionally upto just under
|
||||||
|
the leading bit of b. This saves alot of multiple precision shifting.
|
||||||
|
*/
|
||||||
|
internal_int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
/*
|
||||||
|
How many bits of last digit does b use.
|
||||||
|
*/
|
||||||
|
bits := internal_count_bits(b) % _DIGIT_BITS;
|
||||||
|
|
||||||
|
if b.used > 1 {
|
||||||
|
power := ((b.used - 1) * _DIGIT_BITS) + bits - 1;
|
||||||
|
internal_int_power_of_two(a, power) or_return;
|
||||||
|
} else {
|
||||||
|
internal_one(a);
|
||||||
|
bits = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now compute C = A * B mod b.
|
||||||
|
*/
|
||||||
|
for x := bits - 1; x < _DIGIT_BITS; x += 1 {
|
||||||
|
internal_int_shl1(a, a) or_return;
|
||||||
|
if internal_cmp_mag(a, b) != -1 {
|
||||||
|
internal_sub(a, a, b) or_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_montgomery_calc_normalization :: proc(a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
assert_if_nil(a, b);
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
|
|
||||||
|
return #force_inline internal_int_montgomery_calc_normalization(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets up the Montgomery reduction stuff.
|
||||||
|
*/
|
||||||
|
internal_int_montgomery_setup :: proc(n: ^Int) -> (rho: DIGIT, err: Error) {
|
||||||
|
/*
|
||||||
|
Fast inversion mod 2**k
|
||||||
|
Based on the fact that:
|
||||||
|
|
||||||
|
XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
|
||||||
|
=> 2*X*A - X*X*A*A = 1
|
||||||
|
=> 2*(1) - (1) = 1
|
||||||
|
*/
|
||||||
|
b := n.digit[0];
|
||||||
|
if b & 1 == 0 { return 0, .Invalid_Argument; }
|
||||||
|
|
||||||
|
x := (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
|
||||||
|
x *= 2 - (b * x); /* here x*a==1 mod 2**8 */
|
||||||
|
x *= 2 - (b * x); /* here x*a==1 mod 2**16 */
|
||||||
|
when _WORD_TYPE_BITS == 64 {
|
||||||
|
x *= 2 - (b * x); /* here x*a==1 mod 2**32 */
|
||||||
|
x *= 2 - (b * x); /* here x*a==1 mod 2**64 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
rho = -1/m mod b
|
||||||
|
*/
|
||||||
|
rho = DIGIT(((_WORD(1) << _WORD(_DIGIT_BITS)) - _WORD(x)) & _WORD(_MASK));
|
||||||
|
return rho, nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_montgomery_setup :: proc(n: ^Int, allocator := context.allocator) -> (rho: DIGIT, err: Error) {
|
||||||
|
assert_if_nil(n);
|
||||||
|
internal_clear_if_uninitialized(n, allocator) or_return;
|
||||||
|
|
||||||
|
return #force_inline internal_int_montgomery_setup(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the number of Rabin-Miller trials needed for a given bit size.
|
||||||
|
*/
|
||||||
number_of_rabin_miller_trials :: proc(bit_size: int) -> (number_of_trials: int) {
|
number_of_rabin_miller_trials :: proc(bit_size: int) -> (number_of_trials: int) {
|
||||||
switch {
|
switch {
|
||||||
case bit_size <= 80:
|
case bit_size <= 80:
|
||||||
|
|||||||
+356
-20
@@ -113,7 +113,7 @@ _private_int_mul_toom :: proc(dest, a, b: ^Int, allocator := context.allocator)
|
|||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
S1, S2, T1, a0, a1, a2, b0, b1, b2 := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
S1, S2, T1, a0, a1, a2, b0, b1, b2 := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(S1, S2, T1, a0, a1, a2, b0, b1, b2);
|
defer internal_destroy(S1, S2, T1, a0, a1, a2, b0, b1, b2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Init temps.
|
Init temps.
|
||||||
@@ -258,7 +258,7 @@ _private_int_mul_karatsuba :: proc(dest, a, b: ^Int, allocator := context.alloca
|
|||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|
||||||
x0, x1, y0, y1, t1, x0y0, x1y1 := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
x0, x1, y0, y1, t1, x0y0, x1y1 := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer destroy(x0, x1, y0, y1, t1, x0y0, x1y1);
|
defer internal_destroy(x0, x1, y0, y1, t1, x0y0, x1y1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
min # of digits, divided by two.
|
min # of digits, divided by two.
|
||||||
@@ -426,6 +426,195 @@ _private_int_mul_comba :: proc(dest, a, b: ^Int, digits: int, allocator := conte
|
|||||||
return internal_clamp(dest);
|
return internal_clamp(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Multiplies |a| * |b| and does not compute the lower digs digits
|
||||||
|
[meant to get the higher part of the product]
|
||||||
|
*/
|
||||||
|
_private_int_mul_high :: proc(dest, a, b: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Can we use the fast multiplier?
|
||||||
|
*/
|
||||||
|
if a.used + b.used + 1 < _WARRAY && min(a.used, b.used) < _MAX_COMBA {
|
||||||
|
return _private_int_mul_high_comba(dest, a, b, digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_grow(dest, a.used + b.used + 1) or_return;
|
||||||
|
dest.used = a.used + b.used + 1;
|
||||||
|
|
||||||
|
pa := a.used;
|
||||||
|
pb := b.used;
|
||||||
|
for ix := 0; ix < pa; ix += 1 {
|
||||||
|
carry := DIGIT(0);
|
||||||
|
|
||||||
|
for iy := digits - ix; iy < pb; iy += 1 {
|
||||||
|
/*
|
||||||
|
Calculate the double precision result.
|
||||||
|
*/
|
||||||
|
r := _WORD(dest.digit[ix + iy]) + _WORD(a.digit[ix]) * _WORD(b.digit[iy]) + _WORD(carry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the lower part.
|
||||||
|
*/
|
||||||
|
dest.digit[ix + iy] = DIGIT(r & _WORD(_MASK));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Carry the carry.
|
||||||
|
*/
|
||||||
|
carry = DIGIT(r >> _WORD(_DIGIT_BITS));
|
||||||
|
}
|
||||||
|
dest.digit[ix + pb] = carry;
|
||||||
|
}
|
||||||
|
return internal_clamp(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a modified version of `_private_int_mul_comba` that only produces output digits *above* `digits`.
|
||||||
|
See the comments for `_private_int_mul_comba` to see how it works.
|
||||||
|
|
||||||
|
This is used in the Barrett reduction since for one of the multiplications
|
||||||
|
only the higher digits were needed. This essentially halves the work.
|
||||||
|
|
||||||
|
Based on Algorithm 14.12 on pp.595 of HAC.
|
||||||
|
*/
|
||||||
|
_private_int_mul_high_comba :: proc(dest, a, b: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
W: [_WARRAY]DIGIT = ---;
|
||||||
|
_W: _WORD = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Number of output digits to produce. Grow the destination as required.
|
||||||
|
*/
|
||||||
|
pa := a.used + b.used;
|
||||||
|
internal_grow(dest, pa) or_return;
|
||||||
|
|
||||||
|
ix: int;
|
||||||
|
for ix = digits; ix < pa; ix += 1 {
|
||||||
|
/*
|
||||||
|
Get offsets into the two bignums.
|
||||||
|
*/
|
||||||
|
ty := min(b.used - 1, ix);
|
||||||
|
tx := ix - ty;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the number of times the loop will iterrate, essentially it's
|
||||||
|
while (tx++ < a->used && ty-- >= 0) { ... }
|
||||||
|
*/
|
||||||
|
iy := min(a.used - tx, ty + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Execute loop.
|
||||||
|
*/
|
||||||
|
for iz := 0; iz < iy; iz += 1 {
|
||||||
|
_W += _WORD(a.digit[tx + iz]) * _WORD(b.digit[ty - iz]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Store term.
|
||||||
|
*/
|
||||||
|
W[ix] = DIGIT(_W) & DIGIT(_MASK);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make next carry.
|
||||||
|
*/
|
||||||
|
_W = _W >> _WORD(_DIGIT_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Setup dest
|
||||||
|
*/
|
||||||
|
old_used := dest.used;
|
||||||
|
dest.used = pa;
|
||||||
|
|
||||||
|
for ix = digits; ix < pa; ix += 1 {
|
||||||
|
/*
|
||||||
|
Now extract the previous digit [below the carry].
|
||||||
|
*/
|
||||||
|
dest.digit[ix] = W[ix];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Zero remainder.
|
||||||
|
*/
|
||||||
|
internal_zero_unused(dest, old_used);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Adjust dest.used based on leading zeroes.
|
||||||
|
*/
|
||||||
|
return internal_clamp(dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Single-digit multiplication with the smaller number as the single-digit.
|
||||||
|
*/
|
||||||
|
_private_int_mul_balance :: proc(dest, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
a, b := a, b;
|
||||||
|
|
||||||
|
a0, tmp, r := &Int{}, &Int{}, &Int{};
|
||||||
|
defer internal_destroy(a0, tmp, r);
|
||||||
|
|
||||||
|
b_size := min(a.used, b.used);
|
||||||
|
n_blocks := max(a.used, b.used) / b_size;
|
||||||
|
|
||||||
|
internal_grow(a0, b_size + 2) or_return;
|
||||||
|
internal_init_multi(tmp, r) or_return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make sure that `a` is the larger one.
|
||||||
|
*/
|
||||||
|
if a.used < b.used {
|
||||||
|
a, b = b, a;
|
||||||
|
}
|
||||||
|
assert(a.used >= b.used);
|
||||||
|
|
||||||
|
i, j := 0, 0;
|
||||||
|
for ; i < n_blocks; i += 1 {
|
||||||
|
/*
|
||||||
|
Cut a slice off of `a`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a0.used = b_size;
|
||||||
|
internal_copy_digits(a0, a, a0.used, j);
|
||||||
|
j += a0.used;
|
||||||
|
internal_clamp(a0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Multiply with `b`.
|
||||||
|
*/
|
||||||
|
internal_mul(tmp, a0, b) or_return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shift `tmp` to the correct position.
|
||||||
|
*/
|
||||||
|
internal_shl_digit(tmp, b_size * i) or_return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Add to output. No carry needed.
|
||||||
|
*/
|
||||||
|
internal_add(r, r, tmp) or_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The left-overs; there are always left-overs.
|
||||||
|
*/
|
||||||
|
if j < a.used {
|
||||||
|
a0.used = a.used - j;
|
||||||
|
internal_copy_digits(a0, a, a0.used, j);
|
||||||
|
j += a0.used;
|
||||||
|
internal_clamp(a0);
|
||||||
|
|
||||||
|
internal_mul(tmp, a0, b) or_return;
|
||||||
|
internal_shl_digit(tmp, b_size * i) or_return;
|
||||||
|
internal_add(r, r, tmp) or_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal_swap(dest, r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16
|
Low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16
|
||||||
Assumes `dest` and `src` to not be `nil`, and `src` to have been initialized.
|
Assumes `dest` and `src` to not be `nil`, and `src` to have been initialized.
|
||||||
@@ -1188,7 +1377,7 @@ _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int
|
|||||||
|
|
||||||
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
|
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
c: int;
|
c: int;
|
||||||
defer destroy(ta, tb, tq, q);
|
defer internal_destroy(ta, tb, tq, q);
|
||||||
|
|
||||||
for {
|
for {
|
||||||
internal_one(tq) or_return;
|
internal_one(tq) or_return;
|
||||||
@@ -1241,31 +1430,34 @@ _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int
|
|||||||
Binary split factorial algo due to: http://www.luschny.de/math/factorial/binarysplitfact.html
|
Binary split factorial algo due to: http://www.luschny.de/math/factorial/binarysplitfact.html
|
||||||
*/
|
*/
|
||||||
_private_int_factorial_binary_split :: proc(res: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
_private_int_factorial_binary_split :: proc(res: ^Int, n: int, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
inner, outer, start, stop, temp := &Int{}, &Int{}, &Int{}, &Int{}, &Int{};
|
||||||
defer internal_destroy(inner, outer, start, stop, temp);
|
defer internal_destroy(inner, outer, start, stop, temp);
|
||||||
|
|
||||||
internal_one(inner, false, allocator) or_return;
|
internal_one(inner, false) or_return;
|
||||||
internal_one(outer, false, allocator) or_return;
|
internal_one(outer, false) or_return;
|
||||||
|
|
||||||
bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
|
bits_used := int(_DIGIT_TYPE_BITS - intrinsics.count_leading_zeros(n));
|
||||||
|
|
||||||
for i := bits_used; i >= 0; i -= 1 {
|
for i := bits_used; i >= 0; i -= 1 {
|
||||||
start := (n >> (uint(i) + 1)) + 1 | 1;
|
start := (n >> (uint(i) + 1)) + 1 | 1;
|
||||||
stop := (n >> uint(i)) + 1 | 1;
|
stop := (n >> uint(i)) + 1 | 1;
|
||||||
_private_int_recursive_product(temp, start, stop, 0, allocator) or_return;
|
_private_int_recursive_product(temp, start, stop, 0) or_return;
|
||||||
internal_mul(inner, inner, temp, allocator) or_return;
|
internal_mul(inner, inner, temp) or_return;
|
||||||
internal_mul(outer, outer, inner, allocator) or_return;
|
internal_mul(outer, outer, inner) or_return;
|
||||||
}
|
}
|
||||||
shift := n - intrinsics.count_ones(n);
|
shift := n - intrinsics.count_ones(n);
|
||||||
|
|
||||||
return internal_shl(res, outer, int(shift), allocator);
|
return internal_shl(res, outer, int(shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recursive product used by binary split factorial algorithm.
|
Recursive product used by binary split factorial algorithm.
|
||||||
*/
|
*/
|
||||||
_private_int_recursive_product :: proc(res: ^Int, start, stop: int, level := int(0), allocator := context.allocator) -> (err: Error) {
|
_private_int_recursive_product :: proc(res: ^Int, start, stop: int, level := int(0), allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
t1, t2 := &Int{}, &Int{};
|
t1, t2 := &Int{}, &Int{};
|
||||||
defer internal_destroy(t1, t2);
|
defer internal_destroy(t1, t2);
|
||||||
|
|
||||||
@@ -1275,28 +1467,28 @@ _private_int_recursive_product :: proc(res: ^Int, start, stop: int, level := int
|
|||||||
|
|
||||||
num_factors := (stop - start) >> 1;
|
num_factors := (stop - start) >> 1;
|
||||||
if num_factors == 2 {
|
if num_factors == 2 {
|
||||||
internal_set(t1, start, false, allocator) or_return;
|
internal_set(t1, start, false) or_return;
|
||||||
when true {
|
when true {
|
||||||
internal_grow(t2, t1.used + 1, false, allocator) or_return;
|
internal_grow(t2, t1.used + 1, false) or_return;
|
||||||
internal_add(t2, t1, 2, allocator) or_return;
|
internal_add(t2, t1, 2) or_return;
|
||||||
} else {
|
} else {
|
||||||
add(t2, t1, 2) or_return;
|
internal_add(t2, t1, 2) or_return;
|
||||||
}
|
}
|
||||||
return internal_mul(res, t1, t2, allocator);
|
return internal_mul(res, t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if num_factors > 1 {
|
if num_factors > 1 {
|
||||||
mid := (start + num_factors) | 1;
|
mid := (start + num_factors) | 1;
|
||||||
_private_int_recursive_product(t1, start, mid, level + 1, allocator) or_return;
|
_private_int_recursive_product(t1, start, mid, level + 1) or_return;
|
||||||
_private_int_recursive_product(t2, mid, stop, level + 1, allocator) or_return;
|
_private_int_recursive_product(t2, mid, stop, level + 1) or_return;
|
||||||
return internal_mul(res, t1, t2, allocator);
|
return internal_mul(res, t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if num_factors == 1 {
|
if num_factors == 1 {
|
||||||
return #force_inline internal_set(res, start, true, allocator);
|
return #force_inline internal_set(res, start, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return #force_inline internal_one(res, true, allocator);
|
return #force_inline internal_one(res, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1542,6 +1734,126 @@ _private_int_log :: proc(a: ^Int, base: DIGIT, allocator := context.allocator) -
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Computes xR**-1 == x (mod N) via Montgomery Reduction.
|
||||||
|
This is an optimized implementation of `internal_montgomery_reduce`
|
||||||
|
which uses the comba method to quickly calculate the columns of the reduction.
|
||||||
|
Based on Algorithm 14.32 on pp.601 of HAC.
|
||||||
|
*/
|
||||||
|
_private_montgomery_reduce_comba :: proc(x, n: ^Int, rho: DIGIT, allocator := context.allocator) -> (err: Error) {
|
||||||
|
context.allocator = allocator;
|
||||||
|
W: [_WARRAY]_WORD = ---;
|
||||||
|
|
||||||
|
if x.used > _WARRAY { return .Invalid_Argument; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get old used count.
|
||||||
|
*/
|
||||||
|
old_used := x.used;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Grow `x` as required.
|
||||||
|
*/
|
||||||
|
internal_grow(x, n.used + 1) or_return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
First we have to get the digits of the input into an array of double precision words W[...]
|
||||||
|
Copy the digits of `x` into W[0..`x.used` - 1]
|
||||||
|
*/
|
||||||
|
ix: int;
|
||||||
|
for ix = 0; ix < x.used; ix += 1 {
|
||||||
|
W[ix] = _WORD(x.digit[ix]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Zero the high words of W[a->used..m->used*2].
|
||||||
|
*/
|
||||||
|
zero_upper := (n.used * 2) + 1;
|
||||||
|
if ix < zero_upper {
|
||||||
|
for ix = x.used; ix < zero_upper; ix += 1 {
|
||||||
|
W[ix] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now we proceed to zero successive digits from the least significant upwards.
|
||||||
|
*/
|
||||||
|
for ix = 0; ix < n.used; ix += 1 {
|
||||||
|
/*
|
||||||
|
`mu = ai * m' mod b`
|
||||||
|
|
||||||
|
We avoid a double precision multiplication (which isn't required)
|
||||||
|
by casting the value down to a DIGIT. Note this requires
|
||||||
|
that W[ix-1] have the carry cleared (see after the inner loop)
|
||||||
|
*/
|
||||||
|
mu := ((W[ix] & _WORD(_MASK)) * _WORD(rho)) & _WORD(_MASK);
|
||||||
|
|
||||||
|
/*
|
||||||
|
`a = a + mu * m * b**i`
|
||||||
|
|
||||||
|
This is computed in place and on the fly. The multiplication
|
||||||
|
by b**i is handled by offseting which columns the results
|
||||||
|
are added to.
|
||||||
|
|
||||||
|
Note the comba method normally doesn't handle carries in the
|
||||||
|
inner loop In this case we fix the carry from the previous
|
||||||
|
column since the Montgomery reduction requires digits of the
|
||||||
|
result (so far) [see above] to work.
|
||||||
|
|
||||||
|
This is handled by fixing up one carry after the inner loop.
|
||||||
|
The carry fixups are done in order so after these loops the
|
||||||
|
first m->used words of W[] have the carries fixed.
|
||||||
|
*/
|
||||||
|
for iy := 0; iy < n.used; iy += 1 {
|
||||||
|
W[ix + iy] += mu * _WORD(n.digit[iy]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now fix carry for next digit, W[ix+1].
|
||||||
|
*/
|
||||||
|
W[ix + 1] += (W[ix] >> _DIGIT_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now we have to propagate the carries and shift the words downward
|
||||||
|
[all those least significant digits we zeroed].
|
||||||
|
*/
|
||||||
|
|
||||||
|
for ; ix < n.used * 2; ix += 1 {
|
||||||
|
W[ix + 1] += (W[ix] >> _DIGIT_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy out, A = A/b**n
|
||||||
|
*
|
||||||
|
* The result is A/b**n but instead of converting from an
|
||||||
|
* array of mp_word to mp_digit than calling mp_rshd
|
||||||
|
* we just copy them in the right order
|
||||||
|
*/
|
||||||
|
|
||||||
|
for ix = 0; ix < (n.used + 1); ix += 1 {
|
||||||
|
x.digit[ix] = DIGIT(W[n.used + ix] & _WORD(_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set the max used.
|
||||||
|
*/
|
||||||
|
x.used = n.used + 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Zero old_used digits, if the input a was larger than m->used+1 we'll have to clear the digits.
|
||||||
|
*/
|
||||||
|
internal_zero_unused(x, old_used);
|
||||||
|
internal_clamp(x);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if A >= m then A = A - m
|
||||||
|
*/
|
||||||
|
if internal_cmp_mag(x, n) != -1 {
|
||||||
|
return internal_sub(x, x, n);
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
hac 14.61, pp608
|
hac 14.61, pp608
|
||||||
*/
|
*/
|
||||||
@@ -1887,7 +2199,30 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0)) ->
|
|||||||
Tables used by `internal_*` and `_*`.
|
Tables used by `internal_*` and `_*`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_private_prime_table := []DIGIT{
|
_private_int_rem_128 := [?]DIGIT{
|
||||||
|
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||||
|
};
|
||||||
|
#assert(128 * size_of(DIGIT) == size_of(_private_int_rem_128));
|
||||||
|
|
||||||
|
_private_int_rem_105 := [?]DIGIT{
|
||||||
|
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||||
|
0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
|
||||||
|
0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||||
|
0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
|
||||||
|
1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1,
|
||||||
|
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1,
|
||||||
|
};
|
||||||
|
#assert(105 * size_of(DIGIT) == size_of(_private_int_rem_105));
|
||||||
|
|
||||||
|
_private_prime_table := [?]DIGIT{
|
||||||
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
|
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
|
||||||
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
|
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
|
||||||
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
|
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
|
||||||
@@ -1924,6 +2259,7 @@ _private_prime_table := []DIGIT{
|
|||||||
0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
|
0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
|
||||||
0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653,
|
0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653,
|
||||||
};
|
};
|
||||||
|
#assert(256 * size_of(DIGIT) == size_of(_private_prime_table));
|
||||||
|
|
||||||
when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) {
|
when MATH_BIG_FORCE_64_BIT || (!MATH_BIG_FORCE_32_BIT && size_of(rawptr) == 8) {
|
||||||
_factorial_table := [35]_WORD{
|
_factorial_table := [35]_WORD{
|
||||||
|
|||||||
@@ -555,4 +555,19 @@ int_compare_magnitude :: proc(a, b: ^Int, allocator := context.allocator) -> (re
|
|||||||
internal_clear_if_uninitialized(a, b) or_return;
|
internal_clear_if_uninitialized(a, b) or_return;
|
||||||
|
|
||||||
return #force_inline internal_cmp_mag(a, b), nil;
|
return #force_inline internal_cmp_mag(a, b), nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if remainders are possible squares - fast exclude non-squares.
|
||||||
|
|
||||||
|
Returns `true` if `a` is a square, `false` if not.
|
||||||
|
Assumes `a` not to be `nil` and to have been initialized.
|
||||||
|
*/
|
||||||
|
int_is_square :: proc(a: ^Int, allocator := context.allocator) -> (square: bool, err: Error) {
|
||||||
|
assert_if_nil(a);
|
||||||
|
context.allocator = allocator;
|
||||||
|
|
||||||
|
internal_clear_if_uninitialized(a) or_return;
|
||||||
|
|
||||||
|
return #force_inline internal_int_is_square(a);
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ int_to_cstring :: int_itoa_cstring;
|
|||||||
/*
|
/*
|
||||||
Read a string [ASCII] in a given radix.
|
Read a string [ASCII] in a given radix.
|
||||||
*/
|
*/
|
||||||
int_atoi :: proc(res: ^Int, input: string, radix: i8, allocator := context.allocator) -> (err: Error) {
|
int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context.allocator) -> (err: Error) {
|
||||||
assert_if_nil(res);
|
assert_if_nil(res);
|
||||||
input := input;
|
input := input;
|
||||||
context.allocator = allocator;
|
context.allocator = allocator;
|
||||||
|
|||||||
@@ -369,3 +369,22 @@ PyRes :: struct {
|
|||||||
return PyRes{res = r, err = nil};
|
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: Error;
|
||||||
|
square: bool;
|
||||||
|
|
||||||
|
ai := &Int{};
|
||||||
|
defer internal_destroy(ai);
|
||||||
|
|
||||||
|
if err = atoi(ai, string(a), 16); err != nil { return PyRes{res=":is_square:atoi(a):", err=err}; }
|
||||||
|
if square, err = #force_inline 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};
|
||||||
|
}
|
||||||
+41
-17
@@ -160,11 +160,11 @@ print("initialize_constants: ", initialize_constants())
|
|||||||
|
|
||||||
error_string = load(l.test_error_string, [c_byte], c_char_p)
|
error_string = load(l.test_error_string, [c_byte], c_char_p)
|
||||||
|
|
||||||
add = load(l.test_add, [c_char_p, c_char_p], Res)
|
add = load(l.test_add, [c_char_p, c_char_p ], Res)
|
||||||
sub = load(l.test_sub, [c_char_p, c_char_p], Res)
|
sub = load(l.test_sub, [c_char_p, c_char_p ], Res)
|
||||||
mul = load(l.test_mul, [c_char_p, c_char_p], Res)
|
mul = load(l.test_mul, [c_char_p, c_char_p ], Res)
|
||||||
sqr = load(l.test_sqr, [c_char_p ], Res)
|
sqr = load(l.test_sqr, [c_char_p ], Res)
|
||||||
div = load(l.test_div, [c_char_p, c_char_p], Res)
|
div = load(l.test_div, [c_char_p, c_char_p ], Res)
|
||||||
|
|
||||||
# Powers and such
|
# Powers and such
|
||||||
int_log = load(l.test_log, [c_char_p, c_longlong], Res)
|
int_log = load(l.test_log, [c_char_p, c_longlong], Res)
|
||||||
@@ -179,9 +179,11 @@ 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 = load(l.test_shr, [c_char_p, c_longlong], Res)
|
||||||
int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
|
int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
|
||||||
|
|
||||||
int_factorial = load(l.test_factorial, [c_uint64], Res)
|
int_factorial = load(l.test_factorial, [c_uint64 ], Res)
|
||||||
int_gcd = load(l.test_gcd, [c_char_p, c_char_p], Res)
|
int_gcd = load(l.test_gcd, [c_char_p, c_char_p ], Res)
|
||||||
int_lcm = load(l.test_lcm, [c_char_p, c_char_p], Res)
|
int_lcm = load(l.test_lcm, [c_char_p, c_char_p ], Res)
|
||||||
|
|
||||||
|
is_square = load(l.test_is_square, [c_char_p ], Res)
|
||||||
|
|
||||||
def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16):
|
def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16):
|
||||||
passed = True
|
passed = True
|
||||||
@@ -401,14 +403,21 @@ def test_shr_signed(a = 0, bits = 0, expected_error = Error.Okay):
|
|||||||
|
|
||||||
return test("test_shr_signed", res, [a, bits], expected_error, expected_result)
|
return test("test_shr_signed", res, [a, bits], expected_error, expected_result)
|
||||||
|
|
||||||
def test_factorial(n = 0, expected_error = Error.Okay):
|
def test_factorial(number = 0, expected_error = Error.Okay):
|
||||||
args = [n]
|
print("Factorial:", number)
|
||||||
res = int_factorial(*args)
|
args = [number]
|
||||||
|
try:
|
||||||
|
res = int_factorial(*args)
|
||||||
|
except OSError as e:
|
||||||
|
print("{} while trying to factorial {}.".format(e, number))
|
||||||
|
if EXIT_ON_FAIL: exit(3)
|
||||||
|
return False
|
||||||
|
|
||||||
expected_result = None
|
expected_result = None
|
||||||
if expected_error == Error.Okay:
|
if expected_error == Error.Okay:
|
||||||
expected_result = math.factorial(n)
|
expected_result = math.factorial(number)
|
||||||
|
|
||||||
return test("test_factorial", res, [n], expected_error, expected_result)
|
return test("test_factorial", res, [number], expected_error, expected_result)
|
||||||
|
|
||||||
def test_gcd(a = 0, b = 0, expected_error = Error.Okay):
|
def test_gcd(a = 0, b = 0, expected_error = Error.Okay):
|
||||||
args = [arg_to_odin(a), arg_to_odin(b)]
|
args = [arg_to_odin(a), arg_to_odin(b)]
|
||||||
@@ -428,6 +437,15 @@ def test_lcm(a = 0, b = 0, expected_error = Error.Okay):
|
|||||||
|
|
||||||
return test("test_lcm", res, [a, b], expected_error, expected_result)
|
return test("test_lcm", res, [a, b], expected_error, expected_result)
|
||||||
|
|
||||||
|
def test_is_square(a = 0, b = 0, expected_error = Error.Okay):
|
||||||
|
args = [arg_to_odin(a)]
|
||||||
|
res = is_square(*args)
|
||||||
|
expected_result = None
|
||||||
|
if expected_error == Error.Okay:
|
||||||
|
expected_result = str(math.isqrt(a) ** 2 == a) if a > 0 else "False"
|
||||||
|
|
||||||
|
return test("test_is_square", res, [a], expected_error, expected_result)
|
||||||
|
|
||||||
# TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on.
|
# TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on.
|
||||||
#
|
#
|
||||||
# The last two arguments in tests are the expected error and expected result.
|
# The last two arguments in tests are the expected error and expected result.
|
||||||
@@ -527,6 +545,10 @@ TESTS = {
|
|||||||
[ 0, 0, ],
|
[ 0, 0, ],
|
||||||
[ 0, 125,],
|
[ 0, 125,],
|
||||||
],
|
],
|
||||||
|
test_is_square: [
|
||||||
|
[ 12, ],
|
||||||
|
[ 92232459121502451677697058974826760244863271517919321608054113675118660929276431348516553336313179167211015633639725554914519355444316239500734169769447134357534241879421978647995614218985202290368055757891124109355450669008628757662409138767505519391883751112010824030579849970582074544353971308266211776494228299586414907715854328360867232691292422194412634523666770452490676515117702116926803826546868467146319938818238521874072436856528051486567230096290549225463582766830777324099589751817442141036031904145041055454639783559905920619197290800070679733841430619962318433709503256637256772215111521321630777950145713049902839937043785039344243357384899099910837463164007565230287809026956254332260375327814271845678201, ]
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
if not args.fast_tests:
|
if not args.fast_tests:
|
||||||
@@ -545,7 +567,7 @@ RANDOM_TESTS = [
|
|||||||
test_add, test_sub, test_mul, test_sqr, test_div,
|
test_add, test_sub, test_mul, test_sqr, test_div,
|
||||||
test_log, test_pow, test_sqrt, test_root_n,
|
test_log, test_pow, test_sqrt, test_root_n,
|
||||||
test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
|
test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
|
||||||
test_gcd, test_lcm,
|
test_gcd, test_lcm, test_is_square,
|
||||||
]
|
]
|
||||||
SKIP_LARGE = [
|
SKIP_LARGE = [
|
||||||
test_pow, test_root_n, # test_gcd,
|
test_pow, test_root_n, # test_gcd,
|
||||||
@@ -648,11 +670,13 @@ if __name__ == '__main__':
|
|||||||
a = abs(a)
|
a = abs(a)
|
||||||
b = randint(0, 10);
|
b = randint(0, 10);
|
||||||
elif test_proc == test_shl:
|
elif test_proc == test_shl:
|
||||||
b = randint(0, min(BITS, 120));
|
b = randint(0, min(BITS, 120))
|
||||||
elif test_proc == test_shr_signed:
|
elif test_proc == test_shr_signed:
|
||||||
b = randint(0, min(BITS, 120));
|
b = randint(0, min(BITS, 120))
|
||||||
|
elif test_proc == test_is_square:
|
||||||
|
a = randint(0, 1 << BITS)
|
||||||
else:
|
else:
|
||||||
b = randint(0, 1 << BITS)
|
b = randint(0, 1 << BITS)
|
||||||
|
|
||||||
res = None
|
res = None
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user