mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 01:44:36 +00:00
160 lines
4.8 KiB
Odin
160 lines
4.8 KiB
Odin
/*
|
|
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.
|
|
*/
|
|
|
|
//+build ignore
|
|
package math_big
|
|
|
|
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,
|
|
atoi,
|
|
factorial,
|
|
factorial_bin,
|
|
choose,
|
|
lsb,
|
|
ctz,
|
|
sqr,
|
|
bitfield_extract,
|
|
rm_trials,
|
|
is_prime,
|
|
random_prime,
|
|
}
|
|
|
|
Event :: struct {
|
|
ticks: time.Duration,
|
|
count: int,
|
|
cycles: u64,
|
|
}
|
|
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))
|
|
// }
|
|
// }
|
|
|
|
// 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)
|
|
|
|
// 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)
|
|
SCOPED_TIMING :: #force_inline proc(c: Category) -> (ticks: time.Tick, cycles: u64) {
|
|
cycles = time.read_cycle_counter()
|
|
ticks = time.tick_now()
|
|
return
|
|
}
|
|
_SCOPE_END :: #force_inline proc(c: Category, ticks: time.Tick, cycles: u64) {
|
|
cycles_now := time.read_cycle_counter()
|
|
ticks_now := time.tick_now()
|
|
|
|
Timings[c].ticks = time.tick_diff(ticks, ticks_now)
|
|
Timings[c].cycles = cycles_now - cycles
|
|
Timings[c].count += 1
|
|
}
|
|
SCOPED_COUNT_ADD :: #force_inline proc(c: Category, count: int) {
|
|
Timings[c].count += count
|
|
}
|