aboutsummaryrefslogtreecommitdiff
path: root/core/math/big/common.odin
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2021-07-21 13:46:37 +0200
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-11 20:59:50 +0200
commit7648f2e655b0e280bfb049eb02634d0f5cd136ac (patch)
tree2b245d2766e67503f807550997bfe264313a2666 /core/math/big/common.odin
parentd9efa6c8b5cbaaf04c6468f465a6b402b4dc8e82 (diff)
big: Finish big ZII refactor.
Diffstat (limited to 'core/math/big/common.odin')
-rw-r--r--core/math/big/common.odin132
1 files changed, 132 insertions, 0 deletions
diff --git a/core/math/big/common.odin b/core/math/big/common.odin
new file mode 100644
index 000000000..bcbfafaef
--- /dev/null
+++ b/core/math/big/common.odin
@@ -0,0 +1,132 @@
+package big
+
+/*
+ Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
+ Made available under Odin's BSD-2 license.
+
+ An arbitrary precision mathematics implementation in Odin.
+ For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+ The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
+*/
+
+import "core:intrinsics"
+
+/*
+ Tunables
+*/
+_LOW_MEMORY :: #config(BIGINT_SMALL_MEMORY, false);
+when _LOW_MEMORY {
+ _DEFAULT_DIGIT_COUNT :: 8;
+} else {
+ _DEFAULT_DIGIT_COUNT :: 32;
+}
+
+_MUL_KARATSUBA_CUTOFF :: #config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF);
+_SQR_KARATSUBA_CUTOFF :: #config(SQR_KARATSUBA_CUTOFF, _DEFAULT_SQR_KARATSUBA_CUTOFF);
+_MUL_TOOM_CUTOFF :: #config(MUL_TOOM_CUTOFF, _DEFAULT_MUL_TOOM_CUTOFF);
+_SQR_TOOM_CUTOFF :: #config(SQR_TOOM_CUTOFF, _DEFAULT_SQR_TOOM_CUTOFF);
+
+/*
+ These defaults were tuned on an AMD A8-6600K (64-bit) using libTomMath's `make tune`.
+ TODO(Jeroen): Port this tuning algorithm and tune them for more modern processors.
+*/
+_DEFAULT_MUL_KARATSUBA_CUTOFF :: 80;
+_DEFAULT_SQR_KARATSUBA_CUTOFF :: 120;
+_DEFAULT_MUL_TOOM_CUTOFF :: 350;
+_DEFAULT_SQR_TOOM_CUTOFF :: 400;
+
+/*
+ TODO(Jeroen): Decide whether to turn `Sign` into `Flags :: bit_set{Flag; u8}`.
+ This would hold the sign and float class, as appropriate, and would allow us
+ to set an `Int` to +/- Inf, or NaN.
+
+ The operations would need to be updated to propagate these as expected.
+*/
+Sign :: enum u8 {
+ Zero_or_Positive = 0,
+ Negative = 1,
+};
+
+Int :: struct {
+ used: int,
+ digit: [dynamic]DIGIT,
+ sign: Sign,
+};
+
+/*
+ Errors are a strict superset of runtime.Allocation_Error.
+*/
+Error :: enum byte {
+ None = 0,
+ Out_Of_Memory = 1,
+ Invalid_Pointer = 2,
+ Invalid_Argument = 3,
+
+ Unknown_Error = 4,
+ Max_Iterations_Reached = 5,
+ Buffer_Overflow = 6,
+ Integer_Overflow = 7,
+
+ Unimplemented = 127,
+};
+
+Primality_Flag :: enum u8 {
+ Blum_Blum_Shub = 0, /* BBS style prime */
+ Safe = 1, /* Safe prime (p-1)/2 == prime */
+ Second_MSB_On = 3, /* force 2nd MSB to 1 */
+};
+Primality_Flags :: bit_set[Primality_Flag; u8];
+
+/*
+ How do we store the Ints?
+
+ Minimum number of available digits in `Int`, `_DEFAULT_DIGIT_COUNT` >= `_MIN_DIGIT_COUNT`
+ - Must be at least 3 for `_div_school`.
+ - Must be large enough such that `init_integer` can store `u128` in the `Int` without growing.
+ */
+
+_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS);
+#assert(_DEFAULT_DIGIT_COUNT >= _MIN_DIGIT_COUNT);
+
+/*
+ Maximum number of digits.
+ - Must be small enough such that `_bit_count` does not overflow.
+ - Must be small enough such that `_radix_size` for base 2 does not overflow.
+ `_radix_size` needs two additional bytes for zero termination and sign.
+*/
+_MAX_BIT_COUNT :: (max(int) - 2);
+_MAX_DIGIT_COUNT :: _MAX_BIT_COUNT / _DIGIT_BITS;
+
+when size_of(rawptr) == 8 {
+ /*
+ We can use u128 as an intermediary.
+ */
+ DIGIT :: distinct(u64);
+ _WORD :: distinct(u128);
+} else {
+ DIGIT :: distinct(u32);
+ _WORD :: distinct(u64);
+}
+#assert(size_of(_WORD) == 2 * size_of(DIGIT));
+
+_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT);
+_WORD_TYPE_BITS :: 8 * size_of(_WORD);
+
+_DIGIT_BITS :: _DIGIT_TYPE_BITS - 4;
+_WORD_BITS :: 2 * _DIGIT_BITS;
+
+_MASK :: (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1);
+_DIGIT_MAX :: _MASK;
+_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) ;
+_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1);
+
+Order :: enum i8 {
+ LSB_First = -1,
+ MSB_First = 1,
+};
+
+Endianness :: enum i8 {
+ Little = -1,
+ Platform = 0,
+ Big = 1,
+}; \ No newline at end of file