aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2021-09-06 23:35:57 +0200
committerGitHub <noreply@github.com>2021-09-06 23:35:57 +0200
commitfd256002b3190076bb91ec3e02ae17c858222eb5 (patch)
treef1685fb349c00c2c5c19a169c11f3a45544a5b34
parentb0edac58b93e5ef619af393d554ec3ecaa510e8c (diff)
parent48bfce2efcf99d2b79bdbb19ae451973a757d006 (diff)
Merge pull request #1130 from Kelimion/bigint
big: Remove `core:fmt` usage + Add a little demo to examples/demo.
-rw-r--r--core/math/big/build.bat2
-rw-r--r--core/math/big/common.odin1
-rw-r--r--core/math/big/example.odin152
-rw-r--r--core/math/big/helpers.odin2
-rw-r--r--core/math/big/tune.odin124
-rw-r--r--examples/demo/demo.odin78
6 files changed, 179 insertions, 180 deletions
diff --git a/core/math/big/build.bat b/core/math/big/build.bat
index b41694523..308f45d31 100644
--- a/core/math/big/build.bat
+++ b/core/math/big/build.bat
@@ -5,7 +5,7 @@
set TEST_ARGS=-fast-tests
:set TEST_ARGS=
: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 -no-bounds-check -define:MATH_BIG_EXE=false && python test.py %TEST_ARGS%
+: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:size -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 %TEST_ARGS%
:odin build . -build-mode:shared -show-timings -o:speed -define:MATH_BIG_EXE=false && python test.py -fast-tests %TEST_ARGS% \ No newline at end of file
diff --git a/core/math/big/common.odin b/core/math/big/common.odin
index 3fb7601c0..5b7d162bc 100644
--- a/core/math/big/common.odin
+++ b/core/math/big/common.odin
@@ -174,6 +174,7 @@ Error :: enum int {
}
Error_String :: #partial [Error]string{
+ .Okay = "Okay",
.Out_Of_Memory = "Out of memory",
.Invalid_Pointer = "Invalid pointer",
.Invalid_Argument = "Invalid argument",
diff --git a/core/math/big/example.odin b/core/math/big/example.odin
deleted file mode 100644
index 695f6a72f..000000000
--- a/core/math/big/example.odin
+++ /dev/null
@@ -1,152 +0,0 @@
-//+ignore
-/*
- Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
- Made available under Odin's BSD-3 license.
-
- A BigInt 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.
-*/
-package math_big
-
-
-import "core:fmt"
-import "core:mem"
-
-print_configation :: proc() {
- fmt.printf(
-`
-Configuration:
- _DIGIT_BITS %v
- _SMALL_MEMORY %v
- _MIN_DIGIT_COUNT %v
- _MAX_DIGIT_COUNT %v
- _DEFAULT_DIGIT_COUNT %v
- _MAX_COMBA %v
- _WARRAY %v
- _TAB_SIZE %v
- _MAX_WIN_SIZE %v
- MATH_BIG_USE_LUCAS_SELFRIDGE_TEST %v
-Runtime tunable:
- MUL_KARATSUBA_CUTOFF %v
- SQR_KARATSUBA_CUTOFF %v
- MUL_TOOM_CUTOFF %v
- SQR_TOOM_CUTOFF %v
- MAX_ITERATIONS_ROOT_N %v
- FACTORIAL_MAX_N %v
- FACTORIAL_BINARY_SPLIT_CUTOFF %v
- FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS %v
- USE_MILLER_RABIN_ONLY %v
- MAX_ITERATIONS_RANDOM_PRIME %v
-
-`, _DIGIT_BITS,
-_LOW_MEMORY,
-_MIN_DIGIT_COUNT,
-_MAX_DIGIT_COUNT,
-_DEFAULT_DIGIT_COUNT,
-_MAX_COMBA,
-_WARRAY,
-_TAB_SIZE,
-_MAX_WIN_SIZE,
-MATH_BIG_USE_LUCAS_SELFRIDGE_TEST,
-
-MUL_KARATSUBA_CUTOFF,
-SQR_KARATSUBA_CUTOFF,
-MUL_TOOM_CUTOFF,
-SQR_TOOM_CUTOFF,
-MAX_ITERATIONS_ROOT_N,
-FACTORIAL_MAX_N,
-FACTORIAL_BINARY_SPLIT_CUTOFF,
-FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS,
-USE_MILLER_RABIN_ONLY,
-MAX_ITERATIONS_RANDOM_PRIME,
-)
-
-}
-
-print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
- assert_if_nil(a)
-
- as, err := itoa(a, base)
- defer delete(as)
-
- cb := internal_count_bits(a)
- if print_name {
- fmt.printf("%v", name)
- }
- if err != nil {
- fmt.printf("%v (error: %v | %v)", name, err, a)
- }
- fmt.printf("%v", as)
- if print_extra_info {
- fmt.printf(" (base: %v, bits: %v (digits: %v), flags: %v)", base, cb, a.used, a.flags)
- }
- if newline {
- fmt.println()
- }
-}
-
-// printf :: fmt.printf;
-
-demo :: proc() {
- a, b, c, d, e, f, res := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
- defer destroy(a, b, c, d, e, f, res)
-
- bits := 111
- trials := -1
-
- flags := Primality_Flags{}
- fmt.printf("Trying to generate a %v bit prime using %v Miller-Rabin trials and options %v.\n", bits, trials, flags)
-
- err: Error
- {
- SCOPED_TIMING(.random_prime)
- err = internal_random_prime(a, bits, trials, flags)
- }
-
- print("a(10): ", a, 10, true, true, true)
- fmt.printf("err: %v\n", err)
- fmt.printf("RANDOM_PRIME_ITERATIONS_USED: %v\n", RANDOM_PRIME_ITERATIONS_USED)
-
- nails := 0
-
- count := internal_int_pack_count(a, u8, nails)
- buf := make([]u8, count)
- defer delete(buf)
-
- written: int
- order := Order.LSB_First
-
- fmt.printf("\na.digit: %v\n", a.digit[:a.used])
- written, err = internal_int_pack(a, buf, nails, order)
- fmt.printf("\nPacked into buf: %v | err: %v | written: %v\n", buf, err, written)
-
- err = internal_int_unpack(b, buf, nails, order)
- print("\nUnpacked into b: ", b)
- fmt.printf("err: %v\n", err)
- fmt.printf("b.digit: %v\n", b.digit[:b.used])
-}
-
-main :: proc() {
- ta := mem.Tracking_Allocator{}
- mem.tracking_allocator_init(&ta, context.allocator)
- context.allocator = mem.tracking_allocator(&ta)
-
- demo()
-
- print_configation()
-
- print_timings()
-
- if len(ta.allocation_map) > 0 {
- for _, v in ta.allocation_map {
- fmt.printf("Leaked %v bytes @ %v\n", v.size, v.location)
- }
- }
- if len(ta.bad_free_array) > 0 {
- fmt.println("Bad frees:")
- for v in ta.bad_free_array {
- fmt.println(v)
- }
- }
-} \ No newline at end of file
diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin
index ac45c241d..10c9f9e13 100644
--- a/core/math/big/helpers.odin
+++ b/core/math/big/helpers.odin
@@ -11,8 +11,6 @@ package math_big
import "core:intrinsics"
import rnd "core:math/rand"
-// import "core:fmt"
-
/*
TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere.
*/
diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin
index a268f541d..d67ff61b4 100644
--- a/core/math/big/tune.odin
+++ b/core/math/big/tune.odin
@@ -9,8 +9,84 @@
*/
package math_big
-import "core:fmt"
import "core:time"
+import "core:runtime"
+
+print_value :: proc(name: string, value: i64) {
+ runtime.print_string("\t")
+ runtime.print_string(name)
+ runtime.print_string(": ")
+ runtime.print_i64(value)
+ runtime.print_string("\n")
+}
+
+print_bool :: proc(name: string, value: bool) {
+ runtime.print_string("\t")
+ runtime.print_string(name)
+ if value {
+ runtime.print_string(": true\n")
+ } else {
+ runtime.print_string(": false\n")
+ }
+}
+
+print_configation :: proc() {
+ runtime.print_string("Configuration:\n")
+ print_value("_DIGIT_BITS ", _DIGIT_BITS)
+ print_bool ("MATH_BIG_SMALL_MEMORY ", _LOW_MEMORY)
+ print_value("_MIN_DIGIT_COUNT ", _MIN_DIGIT_COUNT)
+ print_value("_MAX_DIGIT_COUNT ", i64(_MAX_DIGIT_COUNT))
+ print_value("_DEFAULT_DIGIT_COUNT ", _DEFAULT_DIGIT_COUNT)
+ print_value("_MAX_COMBA ", _MAX_COMBA)
+ print_value("_WARRAY ", _WARRAY)
+ print_value("_TAB_SIZE ", _TAB_SIZE)
+ print_value("_MAX_WIN_SIZE ", _MAX_WIN_SIZE)
+ print_bool ("MATH_BIG_USE_LUCAS_SELFRIDGE_TEST ", MATH_BIG_USE_LUCAS_SELFRIDGE_TEST)
+
+ runtime.print_string("\nRuntime tunable:\n")
+ print_value("MUL_KARATSUBA_CUTOFF ", i64(MUL_KARATSUBA_CUTOFF))
+ print_value("SQR_KARATSUBA_CUTOFF ", i64(SQR_KARATSUBA_CUTOFF))
+ print_value("MUL_TOOM_CUTOFF ", i64(MUL_TOOM_CUTOFF))
+ print_value("SQR_TOOM_CUTOFF ", i64(SQR_TOOM_CUTOFF))
+ print_value("MAX_ITERATIONS_ROOT_N ", i64(MAX_ITERATIONS_ROOT_N))
+ print_value("FACTORIAL_MAX_N ", i64(FACTORIAL_MAX_N))
+ print_value("FACTORIAL_BINARY_SPLIT_CUTOFF ", i64(FACTORIAL_BINARY_SPLIT_CUTOFF))
+ print_value("FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS", i64(FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS))
+ print_value("FACTORIAL_BINARY_SPLIT_CUTOFF ", i64(FACTORIAL_BINARY_SPLIT_CUTOFF))
+ print_bool ("USE_MILLER_RABIN_ONLY ", USE_MILLER_RABIN_ONLY)
+ print_value("MAX_ITERATIONS_RANDOM_PRIME ", i64(MAX_ITERATIONS_RANDOM_PRIME))
+}
+
+print :: proc(name: string, a: ^Int, base := i8(10), print_name := true, newline := true, print_extra_info := false) {
+ assert_if_nil(a)
+
+ as, err := itoa(a, base)
+ defer delete(as)
+
+ cb := internal_count_bits(a)
+ if print_name {
+ runtime.print_string(name)
+ }
+ if err != nil {
+ runtime.print_string("(Error: ")
+ es := Error_String
+ runtime.print_string(es[err])
+ runtime.print_string(")")
+ }
+ runtime.print_string(as)
+ if print_extra_info {
+ runtime.print_string(" (base: ")
+ runtime.print_i64(i64(base))
+ runtime.print_string(", bits: ")
+ runtime.print_i64(i64(cb))
+ runtime.print_string(", digits: ")
+ runtime.print_i64(i64(a.used))
+ runtime.print_string(")")
+ }
+ if newline {
+ runtime.print_string("\n")
+ }
+}
Category :: enum {
itoa,
@@ -35,32 +111,32 @@ Event :: struct {
Timings := [Category]Event{}
print_timings :: proc() {
- duration :: proc(d: time.Duration) -> (res: string) {
- switch {
- case d < time.Microsecond:
- return fmt.tprintf("%v ns", time.duration_nanoseconds(d))
- case d < time.Millisecond:
- return fmt.tprintf("%v µs", time.duration_microseconds(d))
- case:
- return fmt.tprintf("%v ms", time.duration_milliseconds(d))
- }
- }
+ // duration :: proc(d: time.Duration) -> (res: string) {
+ // switch {
+ // case d < time.Microsecond:
+ // return fmt.tprintf("%v ns", time.duration_nanoseconds(d))
+ // case d < time.Millisecond:
+ // return fmt.tprintf("%v µs", time.duration_microseconds(d))
+ // case:
+ // return fmt.tprintf("%v ms", time.duration_milliseconds(d))
+ // }
+ // }
- for v in Timings {
- if v.count > 0 {
- fmt.println("\nTimings:")
- break
- }
- }
+ // for v in Timings {
+ // if v.count > 0 {
+ // fmt.println("\nTimings:")
+ // break
+ // }
+ // }
- for v, i in Timings {
- if v.count > 0 {
- avg_ticks := time.Duration(f64(v.ticks) / f64(v.count))
- avg_cycles := f64(v.cycles) / f64(v.count)
+ // for v, i in Timings {
+ // if v.count > 0 {
+ // avg_ticks := time.Duration(f64(v.ticks) / f64(v.count))
+ // avg_cycles := f64(v.cycles) / f64(v.count)
- fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count)
- }
- }
+ // fmt.printf("\t%v: %s / %v cycles (avg), %s / %v cycles (total, %v calls)\n", i, duration(avg_ticks), avg_cycles, duration(v.ticks), v.cycles, v.count)
+ // }
+ // }
}
@(deferred_in_out=_SCOPE_END)
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin
index c64c54887..b3471fe87 100644
--- a/examples/demo/demo.odin
+++ b/examples/demo/demo.odin
@@ -8,7 +8,7 @@ import "core:time"
import "core:reflect"
import "core:runtime"
import "core:intrinsics"
-
+import "core:math/big"
/*
The Odin programming language is fast, concise, readable, pragmatic and open sourced.
@@ -2127,6 +2127,81 @@ or_return_operator :: proc() {
foo_2()
}
+arbitrary_precision_maths :: proc() {
+ fmt.println("\n# core:math/big")
+
+ print_bigint :: proc(name: string, a: ^big.Int, base := i8(10), print_name := true, newline := true, print_extra_info := true) {
+ big.assert_if_nil(a)
+
+ as, err := big.itoa(a, base)
+ defer delete(as)
+
+ cb := big.internal_count_bits(a)
+ if print_name {
+ fmt.printf(name)
+ }
+ if err != nil {
+ fmt.printf(" (Error: %v) ", err)
+ }
+ fmt.printf(as)
+ if print_extra_info {
+ fmt.printf(" (base: %v, bits: %v, digits: %v)", base, cb, a.used)
+ }
+ if newline {
+ fmt.println()
+ }
+ }
+
+ a, b, c, d, e, f, res := &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{}
+ defer big.destroy(a, b, c, d, e, f, res)
+
+ // How many bits should the random prime be?
+ bits := 64
+ // Number of Rabin-Miller trials, -1 for automatic.
+ trials := -1
+
+ // Default prime generation flags
+ flags := big.Primality_Flags{}
+
+ err := big.internal_random_prime(a, bits, trials, flags)
+ if err != nil {
+ fmt.printf("Error %v while generating random prime.\n", err)
+ } else {
+ print_bigint("Random Prime A: ", a, 10)
+ fmt.printf("Random number iterations until prime found: %v\n", big.RANDOM_PRIME_ITERATIONS_USED)
+ }
+
+ // If we want to pack this Int into a buffer of u32, how many do we need?
+ count := big.internal_int_pack_count(a, u32)
+ buf := make([]u32, count)
+ defer delete(buf)
+
+ written: int
+ written, err = big.internal_int_pack(a, buf)
+ fmt.printf("\nPacked into u32 buf: %v | err: %v | written: %v\n", buf, err, written)
+
+ // If we want to pack this Int into a buffer of bytes of which only the bottom 6 bits are used, how many do we need?
+ nails := 2
+
+ count = big.internal_int_pack_count(a, u8, nails)
+ byte_buf := make([]u8, count)
+ defer delete(byte_buf)
+
+ written, err = big.internal_int_pack(a, byte_buf, nails)
+ fmt.printf("\nPacked into buf of 6-bit bytes: %v | err: %v | written: %v\n", byte_buf, err, written)
+
+
+
+ // Pick another random big Int, not necesssarily prime.
+ err = big.random(b, 2048)
+ print_bigint("\n2048 bit random number: ", b)
+
+ // Calculate GCD + LCM in one fell swoop
+ big.gcd_lcm(c, d, a, b)
+
+ print_bigint("\nGCD of random prime A and random number B: ", c)
+ print_bigint("\nLCM of random prime A and random number B (in base 36): ", d, 36)
+}
main :: proc() {
when true {
@@ -2162,5 +2237,6 @@ main :: proc() {
relative_data_types()
or_else_operator()
or_return_operator()
+ arbitrary_precision_maths()
}
}