mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 09:54:45 +00:00
Merge pull request #1130 from Kelimion/bigint
big: Remove `core:fmt` usage + Add a little demo to examples/demo.
This commit is contained in:
@@ -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%
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user