core/math/big
math_big
Types
12DIGIT
DIGIT :: u64SourceWe use u128 as an intermediary.
Endianness
Endianness :: enum i8 {
Little = -1,
Platform = 0,
Big = 1,
}SourceError
Error :: enum u8 {
None = 0,
Out_Of_Memory = 1,
Invalid_Pointer = 2,
Invalid_Argument = 3,
Mode_Not_Implemented = 4, // Allocation
Assignment_To_Immutable = 10,
Max_Iterations_Reached = 11,
Buffer_Overflow = 12,
Integer_Overflow = 13,
Integer_Underflow = 14,
Division_by_Zero = 30,
Math_Domain_Error = 31,
Cannot_Open_File = 50,
Cannot_Read_File = 51,
Cannot_Write_File = 52,
Unimplemented = 127,
Okay = None,
}SourceErrors are a strict superset of runtime.Allocation_Error.
Flag
Flag :: enum u8 {
NaN = 0,
Inf = 1,
Immutable = 2,
}SourceFlags
Flags :: bit_set[Flag; u8]SourceInt
Int :: struct {
used: int,
digit: [dynamic]DIGIT,
sign: Sign,
flags: Flags,
}SourceOrder
Order :: enum i8 {
LSB_First = -1,
MSB_First = 1,
}SourcePrimality_Flag
Primality_Flag :: enum u8 {
Blum_Blum_Shub = 0, // Make prime congruent to 3 mod 4
Safe = 1, // Make sure (p-1)/2 is prime as well (implies .Blum_Blum_Shub)
Second_MSB_On = 3, // Make the 2nd highest bit one
}SourcePrimality_Flags
Primality_Flags :: bit_set[Primality_Flag; u8]SourceRat
Rat :: struct {
a: Int,
b: Int,
}SourceSign
Sign :: enum u8 {
Zero_or_Positive = 0,
Negative = 1,
}Source======================= END OF TUNABLES =======================
_WORD
_WORD :: u128SourceConstants
59Error_String
Error_String :: _ = #sparse[Error]string{
.None = "None",
.Out_Of_Memory = "Out of memory",
.Invalid_Pointer = "Invalid pointer",
.Invalid_Argument = "Invalid argument",
.Mode_Not_Implemented = "Allocation mode not implementSourceITOA_COUNT
ITOA_COUNT :: 18SourceITOA_DIVISOR
ITOA_DIVISOR :: DIGIT = DIGIT(1_000_000_000_000_000_000)SourceBase 10 extraction constants
MATH_BIG_USE_FROBENIUS_TEST
MATH_BIG_USE_FROBENIUS_TEST :: _ = !MATH_BIG_USE_LUCAS_SELFRIDGE_TESTSourceMATH_BIG_USE_LUCAS_SELFRIDGE_TEST
MATH_BIG_USE_LUCAS_SELFRIDGE_TEST :: _ = #config(MATH_BIG_USE_LUCAS_SELFRIDGE_TEST, false)Sourceinternal_int_is_prime switchables.
Use Frobenius-Underwood for primality testing, or use Lucas-Selfridge (default).RADIX_TABLE_REVERSE_SIZE
RADIX_TABLE_REVERSE_SIZE :: 80Source_DEFAULT_MUL_KARATSUBA_CUTOFF
_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MATH_BIG_MUL_KARATSUBA_CUTOFF, 80)SourceThese 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.
It would also be cool if we collected some data across various processor families.
This would let uss set reasonable defaults at runtime as this library initializes
itself by using `cpuid` or the ARM equivalent._DEFAULT_MUL_TOOM_CUTOFF
_DEFAULT_MUL_TOOM_CUTOFF :: #config(MATH_BIG_MUL_TOOM_CUTOFF, 350)Source_DEFAULT_SQR_KARATSUBA_CUTOFF
_DEFAULT_SQR_KARATSUBA_CUTOFF :: #config(MATH_BIG_SQR_KARATSUBA_CUTOFF, 120)Source_DEFAULT_SQR_TOOM_CUTOFF
_DEFAULT_SQR_TOOM_CUTOFF :: #config(MATH_BIG_SQR_TOOM_CUTOFF, 400)Source_DIGIT_BITS
_DIGIT_BITS :: _DIGIT_TYPE_BITS - _DIGIT_NAILSSource_DIGIT_MAX
_DIGIT_MAX :: _MASKSource_DIGIT_NAILS
_DIGIT_NAILS :: 1Source_DIGIT_TYPE_BITS
_DIGIT_TYPE_BITS :: 8 * size_of(DIGIT)Source_FROBENIUS_UNDERWOOD_A
_FROBENIUS_UNDERWOOD_A :: 32764Sourcefloor of positive solution of (2^16) - 1 = (a + 4) (2 a + 5)
- TODO: Both values are smaller than N^(1/4), would have to use a bigint
- for
ainstead, but anyabigger than about 120 are already so rare that - it is possible to ignore them and still get enough pseudoprimes.
- But it is still a restriction of the set of available pseudoprimes
- which makes this implementation less secure if used stand-alone.
_LOW_MEMORY
_LOW_MEMORY :: _ = #config(MATH_BIG_SMALL_MEMORY, false)SourceTrade a smaller memory footprint for more processing overhead?
_MASK
_MASK :: _ = (DIGIT(1) << DIGIT(_DIGIT_BITS)) - DIGIT(1)Source_MAX_BIT_COUNT
_MAX_BIT_COUNT :: _ = (max(int) - 2)SourceMaximum number of digits.
- Must be small enough such that
_bit_countdoes not overflow. - Must be small enough such that
_radix_sizefor base 2 does not overflow.
`_radix_size` needs two additional bytes for zero termination and sign._MAX_COMBA
_MAX_COMBA :: 1 << (_WORD_TYPE_BITS - (2 * _DIGIT_BITS))Source_MAX_DIGIT_COUNT
_MAX_DIGIT_COUNT :: _ = _MAX_BIT_COUNT / _DIGIT_BITSSource_MIN_DIGIT_COUNT
_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS)SourceHow 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._PRIME_TAB_SIZE
_PRIME_TAB_SIZE :: 256Source_RADIX_SIZE_SCALE
_RADIX_SIZE_SCALE :: 29SourceOverestimate the size needed for the bigint to string conversion by a very small amount.
The error is about 10^-8; it will overestimate the result by at most 11 elements for
a number of the size 2^(2^31)-1 which is currently the largest possible in this library.
Some short tests gave no results larger than 5 (plus 2 for sign and EOS).
Table of {0, INT(log_2([1..64])*2^p)+1 } where p is the scale
factor defined in MP_RADIX_SIZE_SCALE and INT() extracts the integer part (truncating).
Good for 32 bit "int". Set MP_RADIX_SIZE_SCALE = 61 and recompute values
for 64 bit "int"._WARRAY
_WARRAY :: 1 << ((_WORD_TYPE_BITS - (2 * _DIGIT_BITS)) + 1)Source_WORD_BITS
_WORD_BITS :: 2 * _DIGIT_BITSSource_WORD_TYPE_BITS
_WORD_TYPE_BITS :: 8 * size_of(_WORD)Sourcecmp
cmp :: compareSourcecmp_mag
cmp_mag :: compare_magnitudeSourceeq
eq :: equalsSourceeq_abs
eq_abs :: equals_absSourceexp
exp :: powSourcegt
gt :: greater_thanSourcegt_abs
gt_abs :: greater_than_absSourcegteq
gteq :: greater_than_or_equalSourcegteq_abs
gteq_abs :: greater_than_or_equal_absSourceinternal_cmp
internal_cmp :: internal_compareSourceinternal_cmp_digit
internal_cmp_digit :: internal_compare_digitSourceinternal_cmp_mag
internal_cmp_mag :: internal_compare_magnitudeSourceinternal_eq
internal_eq :: internal_equalsSourceinternal_eq_abs
internal_eq_abs :: internal_equals_absSourceinternal_exp
internal_exp :: powSourceinternal_gt
internal_gt :: internal_greater_thanSourceinternal_gt_abs
internal_gt_abs :: internal_greater_than_absSourceinternal_gte
internal_gte :: internal_greater_than_or_equalSourceinternal_gte_abs
internal_gte_abs :: internal_greater_than_or_equal_absSourceinternal_lt
internal_lt :: internal_less_thanSourceinternal_lt_abs
internal_lt_abs :: internal_less_than_absSourceinternal_lte
internal_lte :: internal_less_than_or_equalSourceinternal_lte_abs
internal_lte_abs :: internal_less_than_or_equal_absSourceinternal_zero
internal_zero :: internal_clearSourceis_neg
is_neg :: is_negativeSourceis_pos
is_pos :: is_positiveSourcelt
lt :: less_thanSourcelt_abs
lt_abs :: less_than_absSourcelteq
lteq :: less_than_or_equalSourcelteq_abs
lteq_abs :: less_than_or_equal_absSourceshl1
shl1 :: doubleSourceshr1
shr1 :: halveSourcezero
zero :: clearSourceVariables
24FACTORIAL_BINARY_SPLIT_CUTOFF
FACTORIAL_BINARY_SPLIT_CUTOFF :: 6100SourceCutoff to switch to int_factorial_binary_split, and its max recursion level.
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS
FACTORIAL_BINARY_SPLIT_MAX_RECURSIONS :: 100SourceFACTORIAL_MAX_N
FACTORIAL_MAX_N :: 1_000_000SourceLargest N for which we'll compute N!
INT_INF
INT_INF :: _ = &Int{}SourceInitialize constants.
INT_MINUS_INF
INT_MINUS_INF :: _ = &Int{}SourceInitialize constants.
INT_MINUS_ONE
INT_MINUS_ONE :: _ = &Int{}SourceInitialize constants.
INT_NAN
INT_NAN :: _ = &Int{}SourceInitialize constants.
INT_ONE
INT_ONE :: _ = &Int{}SourceInitialize constants.
INT_ZERO
INT_ZERO :: _ = &Int{}SourceInitialize constants.
MAX_ITERATIONS_RANDOM_PRIME
MAX_ITERATIONS_RANDOM_PRIME :: 1_000_000SourceHow many times we'll call internal_int_random during random prime generation before we bail out.
Set to 0 or less to try indefinitely.MAX_ITERATIONS_ROOT_N
MAX_ITERATIONS_ROOT_N :: 500SourceMUL_KARATSUBA_CUTOFF
MUL_KARATSUBA_CUTOFF :: _ = _DEFAULT_MUL_KARATSUBA_CUTOFFSourceTODO: Make the tunables runtime adjustable where practical.
This allows to benchmark and/or setting optimized values for a certain CPU without recompiling.MUL_TOOM_CUTOFF
MUL_TOOM_CUTOFF :: _ = _DEFAULT_MUL_TOOM_CUTOFFSourceRADIX_TABLE
RADIX_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"SourceCharacters used in radix conversions.
RADIX_TABLE_REVERSE
RADIX_TABLE_REVERSE :: [80]u8 = [RADIX_TABLE_REVERSE_SIZE]u8{
0x3e, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x01, 0x02, 0x03, 0x04, /* +,-./01234 */
0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56789:;<=> */
0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, /* ?@ABCDSourceRANDOM_PRIME_ITERATIONS_USED
RANDOM_PRIME_ITERATIONS_USED :: intSourceHow many iterations we used for the last random prime.
SQR_KARATSUBA_CUTOFF
SQR_KARATSUBA_CUTOFF :: _ = _DEFAULT_SQR_KARATSUBA_CUTOFFSourceSQR_TOOM_CUTOFF
SQR_TOOM_CUTOFF :: _ = _DEFAULT_SQR_TOOM_CUTOFFSourceUSE_MILLER_RABIN_ONLY
USE_MILLER_RABIN_ONLY :: falseSourceRuntime tunable to use Miller-Rabin primality testing only and skip the above.
_factorial_table
_factorial_table :: [35]_WORD = [35]_WORD{
/* f(00): */ 1,
/* f(01): */ 1,
/* f(02): */ 2,
/* f(03): */ Source_log_bases
_log_bases :: [65]u32 = [65]u32{
0, 0, 0x20000001, 0x14309399, 0x10000001,
0xdc81a35, 0xc611924, 0xb660c9e, 0xaaaaaab, 0xa1849cd,
0x9a209a9, 0x94004e1, 0x8ed19c2, 0x8a5ca7d, 0x867a000,
0x830cee3, 0x8000001, 0x7d42d60, 0x7ac8b32, 0x7887847,
0x7677349Source_private_int_rem_105
_private_int_rem_105 :: [?]DIGIT = [?]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, Source_private_int_rem_128
_private_int_rem_128 :: [?]DIGIT = [?]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,
Source======================== End of private procedures =======================
=============================== Private tables ===============================
Tables used by `internal_*` and `_*`._private_prime_table
_private_prime_table :: [256]DIGIT = [_PRIME_TAB_SIZE]DIGIT{
0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
0x0061, 0x0065, 0x0067, 0x006B, 0x00SourceProcedures
364_itoa_raw_full
_itoa_raw_full :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (written: int, err: Error)SourceStores a bignum as a ASCII string in a given radix (2..64)
The buffer must be appropriately sized. This routine doesn't check._itoa_raw_old
_itoa_raw_old :: proc(a: ^Int, radix: i8, buffer: []u8, zero_terminate: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (written: int, err: Error)SourceOld internal digit extraction procedure. We're keeping this around as ground truth for the tests.
_private_copy_digits
_private_copy_digits :: proc(dest: ^Int, src: ^Int, digits: int, offset: int = int(0)) -> (err: Error)SourceCopies DIGITs from src to dest.
Assumes `src` and `dest` to not be `nil` and have been initialized._private_div_recursion
_private_div_recursion :: proc(quotient: ^Int, remainder: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceDirect implementation of algorithms 1.8 "RecursiveDivRem" and 1.9 "UnbalancedDivision" from:
Brent, Richard P., and Paul Zimmermann. "Modern computer arithmetic"
Vol. 18. Cambridge University Press, 2010
Available online at https://arxiv.org/pdf/1004.4710
pages 19ff. in the above online document._private_dr_is_modulus
_private_dr_is_modulus :: proc(a: ^Int) -> (res: bool)SourceDetermines if a number is a valid DR modulus.
Assumes `a` to not be `nil` and to have been initialized._private_int_div_3
_private_int_div_3 :: proc(quotient: ^Int, numerator: ^Int, allocator: mem.Allocator = context.allocator) -> (remainder: DIGIT, err: Error)SourceDivide by three (based on routine from MPI and the GMP manual).
_private_int_div_recursive
_private_int_div_recursive :: proc(quotient: ^Int, remainder: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source_private_int_div_school
_private_int_div_school :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSigned Integer Division
c*b + d == a [i.e. a/b, c=quotient, d=remainder], HAC pp.598 Algorithm 14.20
Note that the description in HAC is horribly incomplete.
For example, it doesn't consider the case where digits are removed from 'x' in
the inner loop.
It also doesn't consider the case that y has fewer than three digits, etc.
The overall algorithm is as described as 14.20 from HAC but fixed to treat these cases._private_int_div_small
_private_int_div_small :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int) -> (err: Error)SourceSlower bit-bang division... also smaller.
Prefer `_int_div_school` for speed._private_int_dr_reduce
_private_int_dr_reduce :: proc(x: ^Int, n: ^Int, k: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReduce "x" in place modulo "n" using the Diminished Radix algorithm.
Based on algorithm from the paper
"Generating Efficient Primes for Discrete Log Cryptosystems"
Chae Hoon Lim, Pil Joong Lee,
POSTECH Information Research Laboratories
The modulus must be of a special format [see manual].
Has been modified to use algorithm 7.10 from the LTM book instead
Input x must be in the range 0 <= x <= (n-1)**2
Assumes `x` and `n` to not be `nil` and to have been initialized._private_int_dr_setup
_private_int_dr_setup :: proc(a: ^Int) -> (d: DIGIT)SourceDetermines the setup value.
Assumes `a` to not be `nil` and to have been initialized._private_int_exponent_mod
_private_int_exponent_mod :: proc(
res: ^Int,
G: ^Int,
X: ^Int,
P: ^Int,
redmode: int,
allocator: mem.Allocator = context.allocator,
) -> (err: Error)SourceComputes res == G**X mod P.
Assumes `res`, `G`, `X` and `P` to not be `nil` and for `G`, `X` and `P` to have been initialized._private_int_exponent_mod_fast
_private_int_exponent_mod_fast :: proc(
res: ^Int,
G: ^Int,
X: ^Int,
P: ^Int,
redmode: int,
allocator: mem.Allocator = context.allocator,
) -> (err: Error)SourceComputes Y == G**X mod P, HAC pp.616, Algorithm 14.85
Uses a left-to-right `k`-ary sliding window to compute the modular exponentiation.
The value of `k` changes based on the size of the exponent.
Uses Montgomery or Diminished Radix reduction [whichever appropriate]
Assumes `res`, `G`, `X` and `P` to not be `nil` and for `G`, `X` and `P` to have been initialized._private_int_factorial_binary_split
_private_int_factorial_binary_split :: proc(res: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceBinary split factorial algo due to: http://www.luschny.de/math/factorial/binarysplitfact.html
_private_int_gcd_lcm
_private_int_gcd_lcm :: proc(res_gcd: ^Int, res_lcm: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceInternal function computing both GCD using the binary method,
and, if target isn't `nil`, also LCM.
Expects the `a` and `b` to have been initialized
and one or both of `res_gcd` or `res_lcm` not to be `nil`.
If both `a` and `b` are zero, return zero.
If either `a` or `b`, return the other one.
The `gcd` and `lcm` wrappers have already done this test,
but `gcd_lcm` wouldn't have, so we still need to perform it.
If neither result is wanted, we have nothing to do._private_int_log
_private_int_log :: proc(a: ^Int, base: DIGIT, allocator: mem.Allocator = context.allocator) -> (res: int, err: Error)SourceInternal implementation of log.
Assumes `a` not to be `nil` and to have been initialized._private_int_montgomery_calc_normalization
_private_int_montgomery_calc_normalization :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShifts 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.
Assumes `a` and `b` not to be `nil`._private_int_montgomery_reduce
_private_int_montgomery_reduce :: proc(x: ^Int, n: ^Int, rho: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceComputes xR**-1 == x (mod N) via Montgomery Reduction.
Assumes `x` and `n` not to be nil._private_int_montgomery_setup
_private_int_montgomery_setup :: proc(n: ^Int, allocator: mem.Allocator = context.allocator) -> (rho: DIGIT, err: Error)SourceSets up the Montgomery reduction stuff.
_private_int_mul
_private_int_mul :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiplies |a| * |b| and only computes upto digs digits of result.
HAC pp. 595, Algorithm 14.12 Modified so you can control how
many digits of output are created._private_int_mul_balance
_private_int_mul_balance :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSingle-digit multiplication with the smaller number as the single-digit.
_private_int_mul_comba
_private_int_mul_comba :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceFast (comba) multiplier
This is the fast column-array [comba] multiplier. It is
designed to compute the columns of the product first
then handle the carries afterwards. This has the effect
of making the nested loops that compute the columns very
simple and schedulable on super-scalar processors.
This has been modified to produce a variable number of
digits of output so if say only a half-product is required
you don't have to compute the upper half (a feature
required for fast Barrett reduction).
Based on Algorithm 14.12 on pp.595 of HAC._private_int_mul_high
_private_int_mul_high :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiplies |a| * |b| and does not compute the lower digs digits
[meant to get the higher part of the product]_private_int_mul_high_comba
_private_int_mul_high_comba :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThis 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_karatsuba
_private_int_mul_karatsuba :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceproduct = |a| * |b| using Karatsuba Multiplication using three half size multiplications.
Let `B` represent the radix [e.g. 2**_DIGIT_BITS] and let `n` represent
half of the number of digits in the min(a,b)
`a` = `a1` * `B`**`n` + `a0`
`b` = `b`1 * `B`**`n` + `b0`
Then, a * b => 1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0
Note that a1b1 and a0b0 are used twice and only need to be computed once.
So in total three half size (half # of digit) multiplications are performed,
a0b0, a1b1 and (a1+b1)(a0+b0)
Note that a multiplication of half the digits requires 1/4th the number of
single precision multiplications, so in total after one call 25% of the
single precision multiplications are saved.
Note also that the call to `internal_mul` can end up back in this function
if the a0, a1, b0, or b1 are above the threshold.
This is known as divide-and-conquer and leads to the famous O(N**lg(3)) or O(N**1.584)
work which is asymptopically lower than the standard O(N**2) that the
baseline/comba methods use. Generally though, the overhead of this method doesn't pay off
until a certain size is reached, of around 80 used DIGITs._private_int_mul_toom
_private_int_mul_toom :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiplication using the Toom-Cook 3-way algorithm.
Much more complicated than Karatsuba but has a lower asymptotic running time of O(N**1.464).
This algorithm is only particularly useful on VERY large inputs.
(We're talking 1000s of digits here...).
This file contains code from J. Arndt's book "Matters Computational"
and the accompanying FXT-library with permission of the author.
Setup from:
Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007.
The interpolation from above needed one temporary variable more than the interpolation here:
Bodrato, Marco, and Alberto Zanoni. "What about Toom-Cook matrices optimality."
Centro Vito Volterra Universita di Roma Tor Vergata (2006)_private_int_recursive_product
_private_int_recursive_product :: proc(res: ^Int, start: int, stop: int, level: int = int(0), allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRecursive product used by binary split factorial algorithm.
_private_int_reduce
_private_int_reduce :: proc(x: ^Int, m: ^Int, mu: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReduces x mod m, assumes 0 < x < m**2, mu is precomputed via reduce_setup.
From HAC pp.604 Algorithm 14.42
Assumes `x`, `m` and `mu` all not to be `nil` and have been initialized._private_int_reduce_2k
_private_int_reduce_2k :: proc(a: ^Int, n: ^Int, d: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReduces a modulo n, where n is of the form 2**p - d.
_private_int_reduce_2k_l
_private_int_reduce_2k_l :: proc(a: ^Int, n: ^Int, d: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReduces a modulo n where n is of the form 2**p - d
This differs from reduce_2k since "d" can be larger than a single digit._private_int_reduce_2k_setup
_private_int_reduce_2k_setup :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (d: DIGIT, err: Error)SourceDetermines the setup value.
Assumes `a` is not `nil`._private_int_reduce_2k_setup_l
_private_int_reduce_2k_setup_l :: proc(mu: ^Int, P: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceDetermines the setup value.
Assumes `mu` and `P` are not `nil`.
d := (1 << a.bits) - a;_private_int_reduce_is_2k
_private_int_reduce_is_2k :: proc(a: ^Int) -> (reducible: bool, err: Error)SourceDetermines if internal_int_reduce_2k can be used.
Asssumes `a` not to be `nil` and to have been initialized._private_int_reduce_is_2k_l
_private_int_reduce_is_2k_l :: proc(a: ^Int) -> (reducible: bool, err: Error)SourceDetermines if internal_int_reduce_2k_l can be used.
Asssumes `a` not to be `nil` and to have been initialized._private_int_reduce_setup
_private_int_reduce_setup :: proc(mu: ^Int, P: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourcePre-calculate the value required for Barrett reduction.
For a given modulus "P" it calulates the value required in "mu"
Assumes `mu` and `P` are not `nil`._private_int_shl_leg
_private_int_shl_leg :: proc(quotient: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift left by digits * _DIGIT_BITS bits.
_private_int_shr_leg
_private_int_shr_leg :: proc(quotient: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift right by digits * _DIGIT_BITS bits.
_private_int_sqr
_private_int_sqr :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow 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._private_int_sqr_comba
_private_int_sqr_comba :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThe jist of squaring...
You do like mult except the offset of the tmpx [one that starts closer to zero] can't equal the offset of tmpy.
So basically you set up iy like before then you min it with (ty-tx) so that it never happens.
You double all those you add in the inner loop. After that loop you do the squares and add them in.
Assumes `dest` and `src` not to be `nil` and `src` to have been initialized._private_int_sqr_karatsuba
_private_int_sqr_karatsuba :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceKaratsuba squaring, computes dest = src * src using three half-size squarings.
See comments of `_private_int_mul_karatsuba` for details.
It is essentially the same algorithm but merely tuned to perform recursive squarings._private_int_sqr_toom
_private_int_sqr_toom :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSquaring using Toom-Cook 3-way algorithm.
Setup and interpolation from algorithm SQR_3 in Chung, Jaewook, and M. Anwar Hasan. "Asymmetric squaring formulae."
18th IEEE Symposium on Computer Arithmetic (ARITH'07). IEEE, 2007._private_inverse_modulo
_private_inverse_modulo :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcehac 14.61, pp608
_private_inverse_modulo_odd
_private_inverse_modulo_odd :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceComputes the modular inverse via binary extended Euclidean algorithm, that is dest = 1 / a mod b.
Based on slow invmod except this is optimized for the case where `b` is odd,
as per HAC Note 14.64 on pp. 610._private_log_power_of_two
_private_log_power_of_two :: proc(a: ^Int, base: DIGIT) -> (log: int, err: Error)SourceReturns the log2 of an Int.
Assumes `a` not to be `nil` and to have been initialized.
Also assumes `base` is a power of two._private_montgomery_reduce_comba
_private_montgomery_reduce_comba :: proc(x: ^Int, n: ^Int, rho: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceComputes 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._zero
_zero :: proc(data: []DIGIT)Sourceassert_if_nil_int
assert_if_nil_int :: proc(integers, loc = #caller_location)Sourceassert_if_nil_rat
assert_if_nil_rat :: proc(rationals, loc = #caller_location)Sourceassert_initialized
assert_initialized :: proc(a: ^Int, loc = #caller_location)SourceInternal helpers.
clamp
clamp :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceTrim unused digits.
This is used to ensure that leading zero digits are trimmed and the leading "used" digit will be non-zero.
Typically very fast. Also fixes the sign if there are no more leading digits.clear_if_uninitialized_multi
clear_if_uninitialized_multi :: proc(args, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceclear_if_uninitialized_single
clear_if_uninitialized_single :: proc(arg: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcecombinations_with_repetition
combinations_with_repetition :: proc(dest: ^Int, n: int, r: int) -> (error: Error)SourceWith n items, calculate how many ways that r of them can be chosen.
Also known as the multiset coefficient or (n multichoose k).combinations_without_repetition
combinations_without_repetition :: proc(dest: ^Int, n: int, r: int) -> (error: Error)SourceWith n items, calculate how many ways that r of them can be chosen without any repeats.
Also known as the binomial coefficient or (n choose k).copy_digits
copy_digits :: proc(dest: ^Int, src: ^Int, digits: int, offset: int = int(0), allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcecount_bits
count_bits :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (count: int, err: Error)SourceCount bits in an Int.
digit_log
digit_log :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error)Sourceerror_if_immutable_multi
error_if_immutable_multi :: proc(args) -> (err: Error)Sourceerror_if_immutable_single
error_if_immutable_single :: proc(arg: ^Int) -> (err: Error)Sourceilog2
ilog2 :: proc(value: T) -> (log2: T)Sourceint_abs
int_abs :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet dest to |src|.
int_add
int_add :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source===========================
User-level routines
===========================
High-level addition. Handles sign.int_add_digit
int_add_digit :: proc(dest: ^Int, a: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceAdds the unsigned DIGIT immediate to an Int,
such that the `DIGIT` doesn't have to be turned into an `Int` first.
dest = a + digit;int_add_rat
int_add_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_addmod
int_addmod :: proc(remainder: ^Int, number: ^Int, addend: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number + addend) % modulus.
int_atoi
int_atoi :: proc(res: ^Int, input: string, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRead a string [ASCII] in a given radix.
int_bit_and
int_bit_and :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCopyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's 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.
This file contains logical operations like `and`, `or` and `xor`.
The `and`, `or` and `xor` binops differ in two lines only.
We could handle those with a switch, but that adds overhead.
TODO: Implement versions that take a DIGIT immediate.
2's complement `and`, returns `dest = a & b;`int_bit_complement
int_bit_complement :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedest = ~src
int_bit_or
int_bit_or :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source2's complement or, returns dest = a | b;
int_bit_xor
int_bit_xor :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source2's complement xor, returns dest = a ^ b;
int_bitfield_extract
int_bitfield_extract :: proc(a: ^Int, offset: int, count: int, allocator: mem.Allocator = context.allocator) -> (res: _WORD, err: Error)Sourceint_bitfield_extract_single
int_bitfield_extract_single :: proc(a: ^Int, offset: int, allocator: mem.Allocator = context.allocator) -> (bit: _WORD, err: Error)SourceHelpers to extract values from the Int.
int_choose_digit
int_choose_digit :: proc(res: ^Int, n: int, k: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceNumber of ways to choose k items from n items.
Also known as the binomial coefficient.
TODO: Speed up.
Could be done faster by reusing code from factorial and reusing the common "prefix" results for n!, k! and n-k!
We know that n >= k, otherwise we early out with res = 0.
So:
n-k, keep result
n, start from previous result
k, start from previous resultint_clear
int_clear :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceClear Int and resize it to the default size.
int_cmp
int_cmp :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (comparison: int, err: Error)Sourceint_cmp_digit
int_cmp_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (comparison: int, err: Error)Sourceint_cmp_mag
int_cmp_mag :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (res: int, err: Error)Sourceint_compare
int_compare :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (comparison: int, err: Error)SourceCompare two Ints, signed.
int_compare_digit
int_compare_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (comparison: int, err: Error)SourceCompare an Int to an unsigned number upto the size of the backing type.
int_compare_magnitude
int_compare_magnitude :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (res: int, err: Error)SourceCompare the magnitude of two Ints, unsigned.
int_copy
int_copy :: proc(dest: ^Int, src: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCopy one Int to another.
int_count_lsb
int_count_lsb :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (count: int, err: Error)SourceReturns the number of trailing zeroes before the first one.
Differs from regular `ctz` in that 0 returns 0.int_destroy
int_destroy :: proc(integers)SourceTODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere. Deallocates the backing memory of one or more Ints.
int_div
int_div :: proc(quotient: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_div_digit
int_div_digit :: proc(quotient: ^Int, numerator: ^Int, denominator: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_div_rat
int_div_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_divmod
int_divmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedivmod.
Both the quotient and remainder are optional and may be passed a nil.int_divmod_digit
int_divmod_digit :: proc(quotient: ^Int, numerator: ^Int, denominator: DIGIT, allocator: mem.Allocator = context.allocator) -> (remainder: DIGIT, err: Error)Sourceint_double
int_double :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedest = src * 2
dest = src << 1int_equals
int_equals :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (equals: bool, err: Error)Sourcebool := a == b
int_equals_abs
int_equals_abs :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (equals: bool, err: Error)Sourcebool := |a| == |b| Compares the magnitudes only, ignores the sign.
int_equals_digit
int_equals_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (equals: bool, err: Error)Sourcebool := a == b
int_factorial
int_factorial :: proc(res: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_from_bytes_big
int_from_bytes_big :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRead Int from a Big Endian binary representation.
Sign is detected from the first byte if `signed` is true.int_from_bytes_big_python
int_from_bytes_big_python :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRead Int from a Big Endian Python binary representation.
Sign is detected from the first byte if `signed` is true.int_from_bytes_little
int_from_bytes_little :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRead Int from a Little Endian binary representation.
Sign is detected from the last byte if `signed` is true.int_from_bytes_little_python
int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceRead Int from a Little Endian Python binary representation.
Sign is detected from the first byte if `signed` is true.int_gcd
int_gcd :: proc(res: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceGreatest Common Divisor.
int_gcd_lcm
int_gcd_lcm :: proc(res_gcd: ^Int, res_lcm: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceFunction computing both GCD and (if target isn't nil) also LCM.
int_get
int_get :: proc(a: ^Int, T: typeid, allocator: mem.Allocator = context.allocator) -> (res: T, err: Error)SourceTODO: Think about using count_bits to check if the value could be returned completely,
and maybe return max(T), .Integer_Overflow if not?int_get_float
int_get_float :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: f64, err: Error)Sourceint_get_i128
int_get_i128 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: i128, err: Error)Sourceint_get_i32
int_get_i32 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: i32, err: Error)Sourceint_get_i64
int_get_i64 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: i64, err: Error)Sourceint_get_u128
int_get_u128 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: u128, err: Error)Sourceint_get_u32
int_get_u32 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: u32, err: Error)Sourceint_get_u64
int_get_u64 :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: u64, err: Error)Sourceint_greater_than
int_greater_than :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (greater_than: bool, err: Error)Sourcebool := a > b
int_greater_than_abs
int_greater_than_abs :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (greater_than: bool, err: Error)Sourcebool := |a| > |b| Compares the magnitudes only, ignores the sign.
int_greater_than_digit
int_greater_than_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (greater_than: bool, err: Error)Sourcebool := a > b
int_greater_than_or_equal
int_greater_than_or_equal :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (greater_than_or_equal: bool, err: Error)Sourcebool := a >= b
int_greater_than_or_equal_abs
int_greater_than_or_equal_abs :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (greater_than_or_equal: bool, err: Error)Sourcebool := |a| >= |b| Compares the magnitudes only, ignores the sign.
int_greater_than_or_equal_digit
int_greater_than_or_equal_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (greater_than_or_equal: bool, err: Error)Sourcebool := a >= b
int_grow
int_grow :: proc(a: ^Int, digits: int, allow_shrink: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_halve
int_halve :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedest = src / 2
dest = src >> 1int_inf
int_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to Inf and optionally shrink it to the minimum backing size.
int_init_multi
int_init_multi :: proc(integers, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceAllocates several Ints at once.
int_is_even
int_is_even :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (even: bool, err: Error)Sourceint_is_initialized
int_is_initialized :: proc(a: ^Int) -> (bool)SourceComparison routines.
int_is_negative
int_is_negative :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (negative: bool, err: Error)Sourceint_is_odd
int_is_odd :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (odd: bool, err: Error)Sourceint_is_positive
int_is_positive :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (positive: bool, err: Error)Sourceint_is_power_of_two
int_is_power_of_two :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: bool, err: Error)Sourceint_is_square
int_is_square :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (square: bool, err: Error)SourceCheck 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_zero
int_is_zero :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (zero: bool, err: Error)Sourceint_itoa_cstring
int_itoa_cstring :: proc(a: ^Int, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (res: cstring, err: Error)SourceThis version of itoa allocates on behalf of the caller. The caller must free the string.
The radix defaults to 10.int_itoa_raw
int_itoa_raw :: proc(a: ^Int, radix: i8, buffer: []u8, size: int = int(-1), zero_terminate: untyped boolean = false) -> (written: int, err: Error)SourceA low-level itoa using a caller-provided buffer. itoa_string and itoa_cstring use this.
You can use also use it if you want to pre-allocate a buffer and optionally reuse it.
Use `radix_size` or `radix_size_estimate` to determine a buffer size big enough.
You can pass the output of `radix_size` to `size` if you've previously called it to size
the output buffer. If you haven't, this routine will call it. This way it knows if the buffer
is the appropriate size, and we can write directly in place without a reverse step at the end.
=== === === IMPORTANT === === ===
If you determined the buffer size using `radix_size_estimate`, or have a buffer
that you reuse that you know is large enough, don't pass this size unless you know what you are doing,
because we will always write backwards starting at last byte of the buffer.
Keep in mind that if you set `size` yourself and it's smaller than the buffer,
it'll result in buffer overflows, as we use it to avoid reversing at the end
and having to perform a buffer overflow check each character.int_itoa_string
int_itoa_string :: proc(a: ^Int, radix: i8 = i8(10), zero_terminate: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (res: string, err: Error)SourceThis version of itoa allocates on behalf of the caller. The caller must free the string.
The radix defaults to 10.int_lcm
int_lcm :: proc(res: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLeast Common Multiple.
int_less_than
int_less_than :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (less_than: bool, err: Error)Sourcebool := a < b
int_less_than_abs
int_less_than_abs :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (less_than: bool, err: Error)Sourcebool := |a| < |b| Compares the magnitudes only, ignores the sign.
int_less_than_digit
int_less_than_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (less_than: bool, err: Error)Sourcebool := a < b
int_less_than_or_equal
int_less_than_or_equal :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (less_than_or_equal: bool, err: Error)Sourcebool := a <= b
int_less_than_or_equal_abs
int_less_than_or_equal_abs :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (less_than_or_equal: bool, err: Error)Sourcebool := |a| <= |b| Compares the magnitudes only, ignores the sign.
int_less_than_or_equal_digit
int_less_than_or_equal_digit :: proc(a: ^Int, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (less_than_or_equal: bool, err: Error)Sourcebool := a <= b
int_log
int_log :: proc(a: ^Int, base: DIGIT, allocator: mem.Allocator = context.allocator) -> (res: int, err: Error)SourceLogs and roots and such.
int_minus_inf
int_minus_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to -Inf and optionally shrink it to the minimum backing size.
int_minus_one
int_minus_one :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to -1 and optionally shrink it to the minimum backing size.
int_mod
int_mod :: proc(remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = numerator % denominator.
0 <= remainder < denominator if denominator > 0
denominator < remainder <= 0 if denominator < 0int_mod_bits
int_mod_bits :: proc(remainder: ^Int, numerator: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = numerator % (1 << bits)
int_mod_digit
int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator: mem.Allocator = context.allocator) -> (remainder: DIGIT, err: Error)Sourceint_mul
int_mul :: proc(dest: ^Int, src: ^Int, multiplier: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceHigh level multiplication (handles sign).
int_mul_digit
int_mul_digit :: proc(dest: ^Int, src: ^Int, multiplier: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiply by a DIGIT.
int_mul_rat
int_mul_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_mulmod
int_mulmod :: proc(remainder: ^Int, number: ^Int, multiplicand: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number * multiplicand) % modulus.
int_nan
int_nan :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to NaN and optionally shrink it to the minimum backing size.
int_neg
int_neg :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet dest to -src.
int_one
int_one :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to 1 and optionally shrink it to the minimum backing size.
int_pow
int_pow :: proc(dest: ^Int, base: ^Int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCalculate dest = base^power using a square-multiply algorithm.
int_pow_int
int_pow_int :: proc(dest: ^Int, base: int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCalculate dest = base^power using a square-multiply algorithm.
int_random
int_random :: proc(dest: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_random_digit
int_random_digit :: proc() -> (res: DIGIT)Sourceint_root_n
int_root_n :: proc(dest: ^Int, src: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceFind the nth root of an Integer.
Result found such that `(dest)**n <= src` and `(dest+1)**n > src`
This algorithm uses Newton's approximation `x[i+1] = x[i] - f(x[i])/f'(x[i])`,
which will find the root in `log(n)` time where each step involves a fair bit.int_set_from_integer
int_set_from_integer :: proc(dest: ^Int, src: T, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceHelpers to set an Int to a specific value.
int_shl
int_shl :: proc(dest: ^Int, src: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift left by a certain bit count.
int_shr
int_shr :: proc(dest: ^Int, source: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_shr_signed
int_shr_signed :: proc(dest: ^Int, src: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift right by a certain bit count with sign extension.
int_shrmod
int_shrmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcequotient, remainder := numerator >> bits;
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.int_sqr
int_sqr :: proc(dest: ^Int, src: ^Int) -> (err: Error)Sourceint_sqrmod
int_sqrmod :: proc(remainder: ^Int, number: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number * number) % modulus.
int_sqrt
int_sqrt :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThis function is less generic than root_n, simpler and faster.
int_sub
int_sub :: proc(dest: ^Int, number: ^Int, decrease: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceHigh-level subtraction, dest = number - decrease. Handles signs.
int_sub_digit
int_sub_digit :: proc(dest: ^Int, a: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceAdds the unsigned DIGIT immediate to an Int,
such that the `DIGIT` doesn't have to be turned into an `Int` first.
dest = a - digit;int_sub_rat
int_sub_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceint_submod
int_submod :: proc(remainder: ^Int, number: ^Int, decrease: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number - decrease) % modulus.
int_swap
int_swap :: proc(a: ^Int, b: ^Int)SourceIn normal code, you can also write a, b = b, a.
However, that only swaps within the current scope.
This helper swaps completely.int_to_bytes_big
int_to_bytes_big :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReturn Big Endian binary representation of a, either signed or unsigned.
If `a` is negative and we ask for the default unsigned representation, we return abs(a).int_to_bytes_big_python
int_to_bytes_big_python :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReturn Python 3.x compatible Big Endian binary representation of a, either signed or unsigned.
If `a` is negative when asking for an unsigned number, we return an error like Python does.int_to_bytes_little
int_to_bytes_little :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReturn Little Endian binary representation of a, either signed or unsigned.
If `a` is negative and we ask for the default unsigned representation, we return abs(a).int_to_bytes_little_python
int_to_bytes_little_python :: proc(a: ^Int, buf: []u8, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReturn Python 3.x compatible Little Endian binary representation of a, either signed or unsigned.
If `a` is negative when asking for an unsigned number, we return an error like Python does.int_to_bytes_size
int_to_bytes_size :: proc(a: ^Int, signed: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (size_in_bytes: int, err: Error)SourceSize binary representation
int_to_cstring
int_to_cstring :: proc(a: ^Int, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (res: cstring, err: Error)Sourceint_to_string
int_to_string :: proc(a: ^Int, radix: i8 = i8(10), zero_terminate: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (res: string, err: Error)Sourceinternal_assert_initialized
internal_assert_initialized :: proc(a: ^Int, loc = #caller_location)SourceInternal helpers.
internal_clamp
internal_clamp :: proc(a: ^Int) -> (err: Error)SourceTrim unused digits.
This is used to ensure that leading zero digits are trimmed and the leading "used" digit will be non-zero.
Typically very fast. Also fixes the sign if there are no more leading digits.internal_clear_if_uninitialized_multi
internal_clear_if_uninitialized_multi :: proc(args, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_clear_if_uninitialized_single
internal_clear_if_uninitialized_single :: proc(arg: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_copy_digits
internal_copy_digits :: proc(dest: ^Int, src: ^Int, digits: int, offset: int = int(0)) -> (err: Error)Sourceinternal_count_bits
internal_count_bits :: proc(a: ^Int) -> (count: int)SourceCount bits in an Int.
Assumes `a` not to be `nil` and to have been initialized.internal_digit_log
internal_digit_log :: proc(a: DIGIT, base: DIGIT) -> (log: int, err: Error)SourceReturns log_base(a), where a is a DIGIT.
internal_error_if_immutable_multi
internal_error_if_immutable_multi :: proc(args) -> (err: Error)Sourceinternal_error_if_immutable_single
internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error)Sourceinternal_get_low_u32
internal_get_low_u32 :: proc(a: ^Int) -> (u32)Sourceinternal_get_low_u64
internal_get_low_u64 :: proc(a: ^Int) -> (u64)Sourceinternal_int_abs
internal_int_abs :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet dest to |src|.
internal_int_add_digit
internal_int_add_digit :: proc(dest: ^Int, a: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level addition Int+DIGIT, signed. Handbook of Applied Cryptography, algorithm 14.7.
Assumptions:
`dest` and `a` != `nil` and have been initalized.
`dest` is large enough (a.used + 1) to fit result.internal_int_add_signed
internal_int_add_signed :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level addition, signed. Handbook of Applied Cryptography, algorithm 14.7.
Assumptions:
`dest`, `a` and `b` != `nil` and have been initalized.internal_int_add_unsigned
internal_int_add_unsigned :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7.
Assumptions:
`dest`, `a` and `b` != `nil` and have been initalized.internal_int_addmod
internal_int_addmod :: proc(remainder: ^Int, number: ^Int, addend: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number + addend) % modulus.
internal_int_allocated_cap
internal_int_allocated_cap :: proc(a: ^Int) -> (cap: int)Source============================= Low-level helpers =============================
`internal_*` helpers don't return an `Error` like their public counterparts do,
because they expect not to be passed `nil` or uninitialized inputs.
This makes them more suitable for `internal_*` functions and some of the
public ones that have already satisfied these constraints.
This procedure returns the allocated capacity of an Int.
Assumes `a` not to be `nil`.internal_int_and
internal_int_and :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThe and, or and xor binops differ in two lines only.
We could handle those with a switch, but that adds overhead.
TODO: Implement versions that take a DIGIT immediate.
2's complement `and`, returns `dest = a & b;`internal_int_bitfield_extract
internal_int_bitfield_extract :: proc(a: ^Int, offset: int, count: int) -> (res: _WORD, err: Error)Sourceinternal_int_bitfield_extract_bool
internal_int_bitfield_extract_bool :: proc(a: ^Int, offset: int) -> (val: bool, err: Error)SourceHelpers to extract values from the Int.
Offset is zero indexed.internal_int_bitfield_extract_single
internal_int_bitfield_extract_single :: proc(a: ^Int, offset: int) -> (bit: _WORD, err: Error)Sourceinternal_int_bitfield_set_single
internal_int_bitfield_set_single :: proc(a: ^Int, offset: int) -> (err: Error)SourceHelpers to (un)set a bit in an Int.
Offset is zero indexed.internal_int_bitfield_toggle_single
internal_int_bitfield_toggle_single :: proc(a: ^Int, offset: int) -> (err: Error)Sourceinternal_int_bitfield_unset_single
internal_int_bitfield_unset_single :: proc(a: ^Int, offset: int) -> (err: Error)Sourceinternal_int_clear
internal_int_clear :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceClear Int and resize it to the default size.
Assumes `a` not to be `nil`.internal_int_compare
internal_int_compare :: proc(a: ^Int, b: ^Int) -> (comparison: int)SourceCompare two Ints, signed.
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`.internal_int_compare_digit
internal_int_compare_digit :: proc(a: ^Int, b: DIGIT) -> (comparison: int)SourceCompare an Int to an unsigned number upto DIGIT & _MASK.
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`.internal_int_compare_magnitude
internal_int_compare_magnitude :: proc(a: ^Int, b: ^Int) -> (comparison: int)SourceCompare the magnitude of two Ints, unsigned.
internal_int_complement
internal_int_complement :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedest = ~src
internal_int_copy
internal_int_copy :: proc(dest: ^Int, src: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCopy one Int to another.
internal_int_count_lsb
internal_int_count_lsb :: proc(a: ^Int) -> (count: int, err: Error)SourceReturns the number of trailing zeroes before the first one.
Differs from regular `ctz` in that 0 returns 0.
Assumes `a` not to be `nil` and have been initialized.internal_int_decr
internal_int_decr :: proc(dest: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_destroy
internal_int_destroy :: proc(integers)SourceOther internal helpers Deallocates the backing memory of one or more Ints.
Asssumes none of the `integers` to be a `nil`.internal_int_div
internal_int_div :: proc(quotient: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceAsssumes quotient, numerator and denominator to have been initialized and not to be nil.
internal_int_divmod
internal_int_divmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedivmod.
Both the quotient and remainder are optional and may be passed a nil.
`numerator` and `denominator` are expected not to be `nil` and have been initialized.internal_int_divmod_digit
internal_int_divmod_digit :: proc(quotient: ^Int, numerator: ^Int, denominator: DIGIT, allocator: mem.Allocator = context.allocator) -> (remainder: DIGIT, err: Error)SourceSingle digit division (based on routine from MPI).
The quotient is optional and may be passed a nil.internal_int_equals
internal_int_equals :: proc(a: ^Int, b: ^Int) -> (equals: bool)Sourcebool := a == b
internal_int_equals_abs
internal_int_equals_abs :: proc(a: ^Int, b: ^Int) -> (equals: bool)Sourcebool := |a| == |b| Compares the magnitudes only, ignores the sign.
internal_int_equals_digit
internal_int_equals_digit :: proc(a: ^Int, b: DIGIT) -> (equals: bool)Sourcebool := a == b
internal_int_exponent_mod
internal_int_exponent_mod :: proc(res: ^Int, G: ^Int, X: ^Int, P: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_extended_euclidean
internal_int_extended_euclidean :: proc(
a: ^Int,
b: ^Int,
U1: ^Int,
U2: ^Int,
U3: ^Int,
allocator: mem.Allocator = context.allocator,
) -> (err: Error)SourceExtended Euclidean algorithm of (a, b) produces a * u1 + b * u2 = u3.
internal_int_factorial
internal_int_factorial :: proc(res: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceTODO: Use Sterling's Approximation to estimate log2(N!) to size the result.
This way we'll have to reallocate less, possibly not at all.internal_int_gcd
internal_int_gcd :: proc(res_gcd: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_gcd_lcm
internal_int_gcd_lcm :: proc(res_gcd: ^Int, res_lcm: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceReturns GCD, LCM or both.
Assumes `a` and `b` to have been initialized.
`res_gcd` and `res_lcm` can be nil or ^Int depending on which results are desired.internal_int_get
internal_int_get :: proc(a: ^Int, T: typeid) -> (res: T, err: Error)SourceTODO: Think about using count_bits to check if the value could be returned completely,
and maybe return max(T), .Integer_Overflow if not?internal_int_get_float
internal_int_get_float :: proc(a: ^Int) -> (res: f64, err: Error)Sourceinternal_int_get_i128
internal_int_get_i128 :: proc(a: ^Int) -> (res: i128, err: Error)Sourceinternal_int_get_i32
internal_int_get_i32 :: proc(a: ^Int) -> (res: i32, err: Error)Sourceinternal_int_get_i64
internal_int_get_i64 :: proc(a: ^Int) -> (res: i64, err: Error)Sourceinternal_int_get_u128
internal_int_get_u128 :: proc(a: ^Int) -> (res: u128, err: Error)Sourceinternal_int_get_u32
internal_int_get_u32 :: proc(a: ^Int) -> (res: u32, err: Error)Sourceinternal_int_get_u64
internal_int_get_u64 :: proc(a: ^Int) -> (res: u64, err: Error)Sourceinternal_int_greater_than
internal_int_greater_than :: proc(a: ^Int, b: ^Int) -> (greater_than: bool)Sourcebool := a > b
internal_int_greater_than_abs
internal_int_greater_than_abs :: proc(a: ^Int, b: ^Int) -> (greater_than: bool)Sourcebool := |a| > |b| Compares the magnitudes only, ignores the sign.
internal_int_greater_than_digit
internal_int_greater_than_digit :: proc(a: ^Int, b: DIGIT) -> (greater_than: bool)Sourcebool := a > b
internal_int_greater_than_or_equal
internal_int_greater_than_or_equal :: proc(a: ^Int, b: ^Int) -> (greater_than_or_equal: bool)Sourcebool := a >= b
internal_int_greater_than_or_equal_abs
internal_int_greater_than_or_equal_abs :: proc(a: ^Int, b: ^Int) -> (greater_than_or_equal: bool)Sourcebool := |a| >= |b| Compares the magnitudes only, ignores the sign.
internal_int_greater_than_or_equal_digit
internal_int_greater_than_or_equal_digit :: proc(a: ^Int, b: DIGIT) -> (greater_than_or_equal: bool)Sourcebool := a >= b
internal_int_grow
internal_int_grow :: proc(a: ^Int, digits: int, allow_shrink: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_incr
internal_int_incr :: proc(dest: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_inf
internal_int_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to Inf and optionally shrink it to the minimum backing size.
internal_int_init_multi
internal_int_init_multi :: proc(integers, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceAllocates several Ints at once.
internal_int_inverse_modulo
internal_int_inverse_modulo :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcehac 14.61, pp608.
internal_int_invmod
internal_int_invmod :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_is_even
internal_int_is_even :: proc(a: ^Int) -> (even: bool)SourceThis procedure will return true if the Int is even, false if not.
Assumes `a` not to be `nil`.internal_int_is_initialized
internal_int_is_initialized :: proc(a: ^Int) -> (initialized: bool)SourceThis procedure will return true if the Int is initialized, false if not.
Assumes `a` not to be `nil`.internal_int_is_negative
internal_int_is_negative :: proc(a: ^Int) -> (negative: bool)SourceThis procedure will return true if the Int is negative, false if not.
Assumes `a` not to be `nil`.internal_int_is_odd
internal_int_is_odd :: proc(a: ^Int) -> (odd: bool)SourceThis procedure will return true if the Int is even, false if not.
Assumes `a` not to be `nil`.internal_int_is_positive
internal_int_is_positive :: proc(a: ^Int) -> (positive: bool)SourceThis procedure will return true if the Int is positive, false if not.
Assumes `a` not to be `nil`.internal_int_is_power_of_two
internal_int_is_power_of_two :: proc(a: ^Int) -> (power_of_two: bool)SourceThis procedure will return true if the Int is a power of two, false if not.
Assumes `a` not to be `nil`.internal_int_is_prime
internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials: int = int(-1), miller_rabin_only = USE_MILLER_RABIN_ONLY, allocator: mem.Allocator = context.allocator) -> (is_prime: bool, err: Error)Sourcea is the big Int to test for primality.
`miller_rabin_trials` can be one of the following:
`< 0`: For `a` up to 3_317_044_064_679_887_385_961_981, set `miller_rabin_trials` to negative to run a predetermined
number of trials for a deterministic answer.
`= 0`: Run Miller-Rabin with bases 2, 3 and one random base < `a`. Non-deterministic.
`> 0`: Run Miller-Rabin with bases 2, 3 and `miller_rabin_trials` number of random bases. Non-deterministic.
`miller_rabin_only`:
`false` Also use either Frobenius-Underwood or Lucas-Selfridge, depending on the compile-time `MATH_BIG_USE_FROBENIUS_TEST` choice.
`true` Run Rabin-Miller trials but skip Frobenius-Underwood / Lucas-Selfridge.
`r` takes a pointer to an instance of `core:math/rand`'s `Rand` and may be `nil` to use the global one.
Returns `is_prime` (bool), where:
`false` Definitively composite.
`true` Probably prime if `miller_rabin_trials` >= 0, with increasing certainty with more trials.
Deterministically prime if `miller_rabin_trials` = 0 for `a` up to 3_317_044_064_679_887_385_961_981.
Assumes `a` not to be `nil` and to have been initialized.internal_int_is_square
internal_int_is_square :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (square: bool, err: Error)SourceCheck 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_zero
internal_int_is_zero :: proc(a: ^Int) -> (zero: bool)SourceThis procedure will return true if the Int is zero, false if not.
Assumes `a` not to be `nil`.internal_int_kronecker
internal_int_kronecker :: proc(a: ^Int, p: ^Int, allocator: mem.Allocator = context.allocator) -> (kronecker: int, err: Error)SourceKronecker/Legendre symbol (a|p)
Straightforward implementation of algorithm 1.4.10 in
Henri Cohen: "A Course in Computational Algebraic Number Theory"
@book{cohen2013course,
title={A course in computational algebraic number theory},
author={Cohen, Henri},
volume={138},
year={2013},
publisher={Springer Science \& Business Media}
}
Assumes `a` and `p` to not be `nil` and to have been initialized.internal_int_lcm
internal_int_lcm :: proc(res_lcm: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_legendre
internal_int_legendre :: proc(a: ^Int, p: ^Int, allocator: mem.Allocator = context.allocator) -> (kronecker: int, err: Error)Sourceinternal_int_less_than
internal_int_less_than :: proc(a: ^Int, b: ^Int) -> (less_than: bool)Sourcebool := a < b
internal_int_less_than_abs
internal_int_less_than_abs :: proc(a: ^Int, b: ^Int) -> (less_than: bool)Sourcebool := |a| < |b| Compares the magnitudes only, ignores the sign.
internal_int_less_than_digit
internal_int_less_than_digit :: proc(a: ^Int, b: DIGIT) -> (less_than: bool)Sourcebool := a < b
internal_int_less_than_or_equal
internal_int_less_than_or_equal :: proc(a: ^Int, b: ^Int) -> (less_than_or_equal: bool)Sourcebool := a <= b
internal_int_less_than_or_equal_abs
internal_int_less_than_or_equal_abs :: proc(a: ^Int, b: ^Int) -> (less_than_or_equal: bool)Sourcebool := |a| <= |b| Compares the magnitudes only, ignores the sign.
internal_int_less_than_or_equal_digit
internal_int_less_than_or_equal_digit :: proc(a: ^Int, b: DIGIT) -> (less_than_or_equal: bool)Sourcebool := a <= b
internal_int_log
internal_int_log :: proc(a: ^Int, base: DIGIT) -> (res: int, err: Error)Source========================= Logs, powers and roots ============================ Returns log_base(a).
Assumes `a` to not be `nil` and have been iniialized.internal_int_minus_inf
internal_int_minus_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to -Inf and optionally shrink it to the minimum backing size.
internal_int_minus_one
internal_int_minus_one :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to -1 and optionally shrink it to the minimum backing size.
internal_int_mod
internal_int_mod :: proc(remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = numerator % denominator.
0 <= remainder < denominator if denominator > 0
denominator < remainder <= 0 if denominator < 0
Asssumes quotient, numerator and denominator to have been initialized and not to be nil.internal_int_mod_bits
internal_int_mod_bits :: proc(remainder: ^Int, numerator: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = numerator % (1 << bits)
Assumes `remainder` and `numerator` both not to be `nil` and `bits` to be >= 0.internal_int_mod_digit
internal_int_mod_digit :: proc(numerator: ^Int, denominator: DIGIT, allocator: mem.Allocator = context.allocator) -> (remainder: DIGIT, err: Error)Sourceinternal_int_mul
internal_int_mul :: proc(dest: ^Int, src: ^Int, multiplier: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceHigh level multiplication (handles sign).
internal_int_mul_denom
internal_int_mul_denom :: proc(dst: ^Int, x: ^Int, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_mul_digit
internal_int_mul_digit :: proc(dest: ^Int, src: ^Int, multiplier: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiply by a DIGIT.
internal_int_mul_integer
internal_int_mul_integer :: proc(dest: ^Int, a: ^Int, b: T, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMultiply bigint a with int d and put the result in dest. Like internal_int_mul_digit but with an integer as the small input.
internal_int_mulmod
internal_int_mulmod :: proc(remainder: ^Int, number: ^Int, multiplicand: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number * multiplicand) % modulus.
internal_int_nan
internal_int_nan :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to NaN and optionally shrink it to the minimum backing size.
internal_int_neg
internal_int_neg :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet dest to -src.
internal_int_one
internal_int_one :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceSet the Int to 1 and optionally shrink it to the minimum backing size.
internal_int_or
internal_int_or :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source2's complement or, returns dest = a | b;
internal_int_pack
internal_int_pack :: proc(a: ^Int, buf: []T, nails: untyped integer = 0, order = Order.LSB_First) -> (written: int, err: Error)SourceBased on gmp's mpz_export.
See https://gmplib.org/manual/Integer-Import-and-Export.html
`buf` is a pre-allocated slice of type `T` "words", which must be an unsigned integer of some description.
Use `internal_int_pack_count(a, T, nails)` to calculate the necessary size.
The library internally uses `DIGIT` as the type, which is u64 or u32 depending on the platform.
You are of course welcome to export to []u8, []u32be, and so forth.
After this you can use `mem.slice_data_cast` to interpret the buffer as bytes if you so choose.
`nails` are the number of top bits the output "word" reserves.
To mimic the internals of this library, this would be 4.
To use the minimum amount of output bytes, set `nails` to 0 and pass a `[]u8`.
IMPORTANT: `pack` serializes the magnitude of an Int, that is, the output is unsigned.
Assumes `a` not to be `nil` and to have been initialized.internal_int_pack_count
internal_int_pack_count :: proc(a: ^Int, T: typeid, nails: untyped integer = 0) -> (size_needed: int)SourceCalculate the size needed for internal_int_pack.
See https://gmplib.org/manual/Integer-Import-and-Export.htmlinternal_int_pow
internal_int_pow :: proc(dest: ^Int, base: ^Int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCalculate dest = base^power using a square-multiply algorithm.
Assumes `dest` and `base` not to be `nil` and to have been initialized.internal_int_pow_int
internal_int_pow_int :: proc(dest: ^Int, base: int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceCalculate dest = base^power.
Assumes `dest` not to be `nil` and to have been initialized.internal_int_power_modulo
internal_int_power_modulo :: proc(res: ^Int, G: ^Int, X: ^Int, P: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThis is a shell function that calls either the normal or Montgomery exptmod functions.
Originally the call to the Montgomery code was embedded in the normal function but that
wasted alot of stack space for nothing (since 99% of the time the Montgomery code would be called).
Computes res == G**X mod P.
Assumes `res`, `G`, `X` and `P` to not be `nil` and for `G`, `X` and `P` to have been initialized.internal_int_power_of_two
internal_int_power_of_two :: proc(a: ^Int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_powmod
internal_int_powmod :: proc(res: ^Int, G: ^Int, X: ^Int, P: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_prime_frobenius_underwood
internal_int_prime_frobenius_underwood :: proc(N: ^Int, allocator: mem.Allocator = context.allocator) -> (result: bool, err: Error)Sourceinternal_int_prime_is_divisible
internal_int_prime_is_divisible :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: bool, err: Error)SourceCopyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's 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.
This file contains prime finding operations.
Determines if an Integer is divisible by one of the _PRIME_TABLE primes.
Returns true if it is, false if not.internal_int_prime_miller_rabin
internal_int_prime_miller_rabin :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (probably_prime: bool, err: Error)SourceMiller-Rabin test of "a" to the base of "b" as described in HAC pp. 139 Algorithm 4.24.
Sets result to `false` if definitely composite or `true` if probably prime.
Randomly the chance of error is no more than 1/4 and often very much lower.
Assumes `a` and `b` not to be `nil` and to have been initialized.internal_int_prime_next_prime
internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceFinds the next prime after the number a using t trials of Miller-Rabin,
in place: It sets `a` to the prime found.
`bbs_style` = true means the prime must be congruent to 3 mod 4internal_int_prime_strong_lucas_selfridge
internal_int_prime_strong_lucas_selfridge :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (lucas_selfridge: bool, err: Error)SourceStrong Lucas-Selfridge test.
returns true if it is a strong L-S prime, false if it is composite
Code ported from Thomas Ray Nicely's implementation of the BPSW test at http://www.trnicely.net/misc/bpsw.html
Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>.
Released into the public domain by the author, who disclaims any legal liability arising from its use.
The multi-line comments are made by Thomas R. Nicely and are copied verbatim.
(If that name sounds familiar, he is the guy who found the fdiv bug in the Pentium CPU.)internal_int_random
internal_int_random :: proc(dest: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_random_digit
internal_int_random_digit :: proc() -> (res: DIGIT)Sourceinternal_int_read_from_ascii_file
internal_int_read_from_ascii_file :: proc(a: ^Int, filename: string, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (err: Error)SourceWe might add functions to read and write byte-encoded Ints from/to files, using int_to_bytes_* functions.
LibTomMath allows exporting/importing to/from a file in ASCII, but it doesn't support a much more compact representation in binary, even though it has several pack functions int_to_bytes_* (which I expanded upon and wrote Python interoperable versions of as well), and (un)pack, which is GMP compatible.
Someone could implement their own read/write binary int procedures, of course.
Could be worthwhile to add a canonical binary file representation with an optional small header that says it's an Odin big.Int, big.Rat or Big.Float, byte count for each component that follows, flag for big/little endian and a flag that says a checksum exists at the end of the file.
For big.Rat and big.Float the header couldn't be optional, because we'd have no way to distinguish where the components end.
Read an Int from an ASCII file.internal_int_root_n
internal_int_root_n :: proc(dest: ^Int, src: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceFind the nth root of an Integer.
Result found such that `(dest)**n <= src` and `(dest+1)**n > src`
This algorithm uses Newton's approximation `x[i+1] = x[i] - f(x[i])/f'(x[i])`,
which will find the root in `log(n)` time where each step involves a fair bit.
Assumes `dest` and `src` not to be `nil` and have been initialized.internal_int_scale_denom
internal_int_scale_denom :: proc(dst: ^Int, x: ^Int, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_set_from_integer
internal_int_set_from_integer :: proc(dest: ^Int, src: T, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceHelpers to set an Int to a specific value.
internal_int_shl
internal_int_shl :: proc(dest: ^Int, src: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift left by a certain bit count.
internal_int_shl1
internal_int_shl1 :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcedest = src * 2
dest = src << 1internal_int_shr
internal_int_shr :: proc(dest: ^Int, source: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_shr1
internal_int_shr1 :: proc(dest: ^Int, src: ^Int) -> (err: Error)Sourcedest = src / 2
dest = src >> 1
Assumes `dest` and `src` not to be `nil` and have been initialized.
We make no allocations here.internal_int_shr_signed
internal_int_shr_signed :: proc(dest: ^Int, src: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceShift right by a certain bit count with sign extension.
internal_int_shrink
internal_int_shrink :: proc(a: ^Int) -> (err: Error)SourceResize backing store.
We don't need to pass the allocator, because the storage itself stores it.
Assumes `a` not to be `nil`, and to have already been initialized.internal_int_shrmod
internal_int_shrmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcequotient, remainder := numerator >> bits;
`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.internal_int_sqrmod
internal_int_sqrmod :: proc(remainder: ^Int, number: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number * number) % modulus.
internal_int_sqrt
internal_int_sqrt :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceThis function is less generic than root_n, simpler and faster.
Assumes `dest` and `src` not to be `nil` and to have been initialized.internal_int_sqrtmod_prime
internal_int_sqrtmod_prime :: proc(res: ^Int, n: ^Int, prime: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceTonelli-Shanks algorithm
https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
https://gmplib.org/list-archives/gmp-discuss/2013-April/005300.htmlinternal_int_sub_digit
internal_int_sub_digit :: proc(dest: ^Int, number: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level subtraction, signed. Handbook of Applied Cryptography, algorithm 14.9.
dest = number - decrease. Assumes |number| > |decrease|.
Assumptions:
`dest`, `number` != `nil` and have been initalized.
`dest` is large enough (number.used + 1) to fit result.internal_int_sub_signed
internal_int_sub_signed :: proc(dest: ^Int, number: ^Int, decrease: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level subtraction, signed. Handbook of Applied Cryptography, algorithm 14.9.
dest = number - decrease. Assumes |number| > |decrease|.
Assumptions:
`dest`, `number` and `decrease` != `nil` and have been initalized.internal_int_sub_unsigned
internal_int_sub_unsigned :: proc(dest: ^Int, number: ^Int, decrease: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceLow-level subtraction, dest = number - decrease. Assumes |number| > |decrease|.
Handbook of Applied Cryptography, algorithm 14.9.
Assumptions:
`dest`, `number` and `decrease` != `nil` and have been initalized.internal_int_submod
internal_int_submod :: proc(remainder: ^Int, number: ^Int, decrease: ^Int, modulus: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceremainder = (number - decrease) % modulus.
internal_int_swap
internal_int_swap :: proc(a: ^Int, b: ^Int)SourceIn normal code, you can also write a, b = b, a.
However, that only swaps within the current scope.
This helper swaps completely.internal_int_unpack
internal_int_unpack :: proc(a: ^Int, buf: []T, nails: untyped integer = 0, order = Order.LSB_First, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_int_write_to_ascii_file
internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (err: Error)SourceWrite an Int to an ASCII file.
internal_int_xor
internal_int_xor :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source2's complement xor, returns dest = a ~ b;
internal_int_zero_unused
internal_int_zero_unused :: proc(dest: ^Int, old_used: untyped integer = -1)Sourceinternal_platform_abs
internal_platform_abs :: proc(n: T) -> (T)Sourceinternal_platform_count_lsb
internal_platform_count_lsb :: proc(a: T) -> (count: int)Sourceinternal_prime_fermat
internal_prime_fermat :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (fermat: bool, err: Error)SourcePerforms one Fermat test.
If "a" were prime then b**a == b (mod a) since the order of
the multiplicative sub-group would be phi(a) = a-1. That means
it would be the same as b**(a mod (a-1)) == b**1 == b (mod a).
Returns `true` if the congruence holds, or `false` otherwise.
Assumes `a` and `b` not to be `nil` and to have been initialized.internal_random_prime
internal_random_prime :: proc(a: ^Int, size_in_bits: int, trials: int, flags: Primality_Flags = Primality_Flags{}, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceMakes a truly random prime of a given size (bits),
Flags are as follows:
Blum_Blum_Shub - Make prime congruent to 3 mod 4
Safe - Make sure (p-1)/2 is prime as well (implies .Blum_Blum_Shub)
Second_MSB_On - Make the 2nd highest bit one
This is possibly the mother of all prime generation functions, muahahahahaha!internal_rat_destroy
internal_rat_destroy :: proc(rationals)Sourceinternal_rat_is_zero
internal_rat_is_zero :: proc(z: ^Rat) -> (bool)Sourceinternal_rat_norm
internal_rat_norm :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceinternal_rat_swap
internal_rat_swap :: proc(a: ^Rat, b: ^Rat)Sourceinternal_rat_to_float
internal_rat_to_float :: proc(T: typeid, z: ^Rat, allocator: mem.Allocator = context.allocator) -> (f: T, exact: bool, err: Error)Sourceinternal_small_pow
internal_small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD)Sourceinternal_sqr
internal_sqr :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (res: Error)Sourcenumber_of_rabin_miller_trials
number_of_rabin_miller_trials :: proc(bit_size: int) -> (number_of_trials: int)SourceReturns the number of Rabin-Miller trials needed for a given bit size.
permutations_with_repetition
permutations_with_repetition :: proc(dest: ^Int, base: int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceWith n items, calculate how many ways that r of them can be ordered.
permutations_without_repetition
permutations_without_repetition :: proc(dest: ^Int, n: int, r: int) -> (error: Error)SourceWith n items, calculate how many ways that r of them can be ordered without any repeats.
platform_abs
platform_abs :: proc(n: T) -> (T)Sourceplatform_count_lsb
platform_count_lsb :: proc(a: T) -> (count: int)Sourceplatform_int_is_power_of_two
platform_int_is_power_of_two :: proc(a: int) -> (bool)Sourcepower_of_two
power_of_two :: proc(a: ^Int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourceradix_size
radix_size :: proc(a: ^Int, radix: i8, zero_terminate: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (size: int, err: Error)SourceWe size for string by default.
rat_abs
rat_abs :: proc(dst: ^Rat, x: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_add_int
rat_add_int :: proc(dst: ^Rat, x: ^Rat, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_add_rat
rat_add_rat :: proc(dst: ^Rat, x: ^Rat, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_compare
rat_compare :: proc(x: ^Rat, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (comparison: int, error: Error)Sourcerat_copy
rat_copy :: proc(dst: ^Rat, src: ^Rat, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_div_int
rat_div_int :: proc(dst: ^Rat, x: ^Rat, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_div_rat
rat_div_rat :: proc(dst: ^Rat, x: ^Rat, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_is_even
rat_is_even :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (ok: bool, err: Error)Sourcerat_is_int
rat_is_int :: proc(z: ^Rat) -> (bool)Sourcerat_is_negative
rat_is_negative :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (ok: bool, err: Error)Sourcerat_is_odd
rat_is_odd :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (ok: bool, err: Error)Sourcerat_is_positive
rat_is_positive :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (ok: bool, err: Error)Sourcerat_is_zero
rat_is_zero :: proc(z: ^Rat) -> (bool)Sourcerat_mul_int
rat_mul_int :: proc(dst: ^Rat, x: ^Rat, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_mul_rat
rat_mul_rat :: proc(dst: ^Rat, x: ^Rat, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_neg
rat_neg :: proc(dst: ^Rat, x: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_digit
rat_set_digit :: proc(dst: ^Rat, a: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_f16
rat_set_f16 :: proc(dst: ^Rat, f: f16, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_f32
rat_set_f32 :: proc(dst: ^Rat, f: f32, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_f64
rat_set_f64 :: proc(dst: ^Rat, f: f64, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_frac_digit
rat_set_frac_digit :: proc(dst: ^Rat, a: DIGIT, b: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_frac_int
rat_set_frac_int :: proc(dst: ^Rat, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_i64
rat_set_i64 :: proc(dst: ^Rat, x: i64, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_int
rat_set_int :: proc(dst: ^Rat, a: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_rat
rat_set_rat :: proc(dst: ^Rat, x: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_set_u64
rat_set_u64 :: proc(dst: ^Rat, x: u64, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_sign
rat_sign :: proc(z: ^Rat) -> (Sign)Sourcerat_sqr
rat_sqr :: proc(dest: ^Rat, src: ^Rat) -> (err: Error)Sourcerat_sub_int
rat_sub_int :: proc(dst: ^Rat, x: ^Rat, y: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_sub_rat
rat_sub_rat :: proc(dst: ^Rat, x: ^Rat, y: ^Rat, allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcerat_swap
rat_swap :: proc(a: ^Rat, b: ^Rat)Sourcerat_to_f16
rat_to_f16 :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (f: f16, exact: bool, err: Error)Sourcerat_to_f32
rat_to_f32 :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (f: f32, exact: bool, err: Error)Sourcerat_to_f64
rat_to_f64 :: proc(z: ^Rat, allocator: mem.Allocator = context.allocator) -> (f: f64, exact: bool, err: Error)Sourceshrink
shrink :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)SourceResize backing store.
small_pow
small_pow :: proc(base: _WORD, exponent: _WORD) -> (result: _WORD)Sourcestring_to_int
string_to_int :: proc(res: ^Int, input: string, radix: i8 = i8(10), allocator: mem.Allocator = context.allocator) -> (err: Error)Sourcezero_unused
zero_unused :: proc(dest: ^Int, old_used: untyped integer = -1)SourceProcedure Groups
155abs
abs :: proc{int_abs, platform_abs, rat_abs}Sourceadd
add :: proc{int_add, int_add_digit, rat_add_rat, rat_add_int, int_add_rat}SourceCopyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's license.
This file collects public proc maps and their aliases.
=== === === === === === === === === === === === === === === === === === === === === === === ===
Basic arithmetic.
See `public.odin`.
=== === === === === === === === === === === === === === === === === === === === === === === ===
High-level addition. Handles sign.addmod
addmod :: proc{int_addmod}Sourceassert_if_nil
assert_if_nil :: proc{assert_if_nil_int, assert_if_nil_rat}Sourceatoi
atoi :: proc{int_atoi}Sourcebit_and
bit_and :: proc{int_bit_and}Sourcebit_complement
bit_complement :: proc{int_bit_complement}Sourcebit_or
bit_or :: proc{int_bit_or}Sourcebit_xor
bit_xor :: proc{int_bit_xor}Sourcechoose
choose :: proc{int_choose_digit}Sourceclear
clear :: proc{int_clear}Sourceclear_if_uninitialized
clear_if_uninitialized :: proc{clear_if_uninitialized_single, clear_if_uninitialized_multi}Sourcecompare
compare :: proc{int_compare, int_compare_digit}Sourcecompare_magnitude
compare_magnitude :: proc{int_compare_magnitude}Sourcecopy
copy :: proc{int_copy, rat_copy}Sourcecount_lsb
count_lsb :: proc{int_count_lsb, platform_count_lsb}Sourcedestroy
destroy :: proc{int_destroy, internal_rat_destroy}Source=== === === === === === === === === === === === === === === === === === === === === === === ===
Initialization and other helpers.
See `helpers.odin`.
=== === === === === === === === === === === === === === === === === === === === === === === ===div
div :: proc{int_div, int_div_digit, rat_div_rat, rat_div_int, int_div_rat}Sourcedivmod
divmod :: proc{int_divmod, int_divmod_digit}Sourcedouble
double :: proc{int_double}Sourceequals
equals :: proc{int_equals, int_equals_digit}Sourceequals_abs
equals_abs :: proc{int_equals_abs}Sourceerror_if_immutable
error_if_immutable :: proc{error_if_immutable_single, error_if_immutable_multi}Sourcefactorial
factorial :: proc{int_factorial}Sourcegcd
gcd :: proc{int_gcd}Sourcegcd_lcm
gcd_lcm :: proc{int_gcd_lcm}Sourceget
get :: proc{int_get}Sourceget_i128
get_i128 :: proc{int_get_i128}Sourceget_i32
get_i32 :: proc{int_get_i32}Sourceget_i64
get_i64 :: proc{int_get_i64}Sourceget_u128
get_u128 :: proc{int_get_u128}Sourceget_u32
get_u32 :: proc{int_get_u32}Sourceget_u64
get_u64 :: proc{int_get_u64}Sourcegreater_than
greater_than :: proc{int_greater_than, int_greater_than_digit}Sourcegreater_than_abs
greater_than_abs :: proc{int_greater_than_abs}Sourcegreater_than_or_equal
greater_than_or_equal :: proc{int_greater_than_or_equal, int_greater_than_or_equal_digit}Sourcegreater_than_or_equal_abs
greater_than_or_equal_abs :: proc{int_greater_than_or_equal_abs}Sourcegrow
grow :: proc{int_grow}Sourcehalve
halve :: proc{int_halve}Sourceinf
inf :: proc{int_inf}Sourceinit_multi
init_multi :: proc{int_init_multi}Sourceinternal_abs
internal_abs :: proc{internal_int_abs, internal_platform_abs}Sourceinternal_add
internal_add :: proc{internal_int_add_signed, internal_int_add_digit}Sourceinternal_add_signed
internal_add_signed :: proc{internal_int_add_signed}Sourceinternal_add_unsigned
internal_add_unsigned :: proc{internal_int_add_unsigned}Sourceinternal_addmod
internal_addmod :: proc{internal_int_addmod}Sourceinternal_and
internal_and :: proc{internal_int_and}Sourceinternal_clear
internal_clear :: proc{internal_int_clear}Sourceinternal_clear_if_uninitialized
internal_clear_if_uninitialized :: proc{internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi}Sourceinternal_compare
internal_compare :: proc{internal_int_compare, internal_int_compare_digit}Sourceinternal_compare_digit
internal_compare_digit :: proc{internal_int_compare_digit}Sourceinternal_compare_magnitude
internal_compare_magnitude :: proc{internal_int_compare_magnitude}Sourceinternal_complement
internal_complement :: proc{internal_int_complement}Sourceinternal_copy
internal_copy :: proc{internal_int_copy}Sourceinternal_count_lsb
internal_count_lsb :: proc{internal_int_count_lsb, internal_platform_count_lsb}Sourceinternal_decr
internal_decr :: proc{internal_int_decr}Sourceinternal_destroy
internal_destroy :: proc{internal_int_destroy, internal_rat_destroy}Sourceinternal_div
internal_div :: proc{internal_int_div}Sourceinternal_divmod
internal_divmod :: proc{internal_int_divmod, internal_int_divmod_digit}Sourceinternal_equals
internal_equals :: proc{internal_int_equals, internal_int_equals_digit}Sourceinternal_equals_abs
internal_equals_abs :: proc{internal_int_equals_abs}Sourceinternal_error_if_immutable
internal_error_if_immutable :: proc{internal_error_if_immutable_single, internal_error_if_immutable_multi}Sourceinternal_get
internal_get :: proc{internal_int_get}Sourceinternal_get_i128
internal_get_i128 :: proc{internal_int_get_i128}Sourceinternal_get_i32
internal_get_i32 :: proc{internal_int_get_i32}Sourceinternal_get_i64
internal_get_i64 :: proc{internal_int_get_i64}Sourceinternal_get_u128
internal_get_u128 :: proc{internal_int_get_u128}Sourceinternal_get_u32
internal_get_u32 :: proc{internal_int_get_u32}Sourceinternal_get_u64
internal_get_u64 :: proc{internal_int_get_u64}Sourceinternal_greater_than
internal_greater_than :: proc{internal_int_greater_than, internal_int_greater_than_digit}Sourceinternal_greater_than_abs
internal_greater_than_abs :: proc{internal_int_greater_than_abs}Sourceinternal_greater_than_or_equal
internal_greater_than_or_equal :: proc{internal_int_greater_than_or_equal, internal_int_greater_than_or_equal_digit}Sourceinternal_greater_than_or_equal_abs
internal_greater_than_or_equal_abs :: proc{internal_int_greater_than_or_equal_abs}Sourceinternal_grow
internal_grow :: proc{internal_int_grow}Sourceinternal_incr
internal_incr :: proc{internal_int_incr}Sourceinternal_inf
internal_inf :: proc{internal_int_inf}Sourceinternal_init_multi
internal_init_multi :: proc{internal_int_init_multi}Sourceinternal_invmod
internal_invmod :: proc{internal_int_inverse_modulo}Sourceinternal_is_even
internal_is_even :: proc{internal_int_is_even}Sourceinternal_is_initialized
internal_is_initialized :: proc{internal_int_is_initialized}Sourceinternal_is_negative
internal_is_negative :: proc{internal_int_is_negative}Sourceinternal_is_odd
internal_is_odd :: proc{internal_int_is_odd}Sourceinternal_is_positive
internal_is_positive :: proc{internal_int_is_positive}Sourceinternal_is_power_of_two
internal_is_power_of_two :: proc{internal_int_is_power_of_two}Sourceinternal_is_zero
internal_is_zero :: proc{internal_rat_is_zero, internal_int_is_zero}Sourceinternal_less_than
internal_less_than :: proc{internal_int_less_than, internal_int_less_than_digit}Sourceinternal_less_than_abs
internal_less_than_abs :: proc{internal_int_less_than_abs}Sourceinternal_less_than_or_equal
internal_less_than_or_equal :: proc{internal_int_less_than_or_equal, internal_int_less_than_or_equal_digit}Sourceinternal_less_than_or_equal_abs
internal_less_than_or_equal_abs :: proc{internal_int_less_than_or_equal_abs}Sourceinternal_log
internal_log :: proc{internal_int_log, internal_digit_log}Sourceinternal_minus_inf
internal_minus_inf :: proc{internal_int_inf}Sourceinternal_minus_one
internal_minus_one :: proc{internal_int_minus_one}Sourceinternal_mod
internal_mod :: proc{internal_int_mod, internal_int_mod_digit}Sourceinternal_mul
internal_mul :: proc{internal_int_mul, internal_int_mul_digit, internal_int_mul_integer}Sourceinternal_mulmod
internal_mulmod :: proc{internal_int_mulmod}Sourceinternal_nan
internal_nan :: proc{internal_int_nan}Sourceinternal_neg
internal_neg :: proc{internal_int_neg}Sourceinternal_one
internal_one :: proc{internal_int_one}Sourceinternal_or
internal_or :: proc{internal_int_or}Sourceinternal_pow
internal_pow :: proc{internal_int_pow, internal_int_pow_int}Sourceinternal_powmod
internal_powmod :: proc{internal_int_power_modulo}Sourceinternal_random
internal_random :: proc{internal_int_random}Sourceinternal_root_n
internal_root_n :: proc{internal_int_root_n}Sourceinternal_set
internal_set :: proc{internal_int_set_from_integer, internal_int_copy, int_atoi}Sourceinternal_shl
internal_shl :: proc{internal_int_shl}Sourceinternal_shr
internal_shr :: proc{internal_int_shr}Sourceinternal_shr_signed
internal_shr_signed :: proc{internal_int_shr_signed}Sourceinternal_shrink
internal_shrink :: proc{internal_int_shrink}Sourceinternal_shrmod
internal_shrmod :: proc{internal_int_shrmod}Sourceinternal_sqrmod
internal_sqrmod :: proc{internal_int_sqrmod}Sourceinternal_sqrt
internal_sqrt :: proc{internal_int_sqrt}Sourceinternal_sub
internal_sub :: proc{internal_int_sub_signed, internal_int_sub_digit}Sourceinternal_sub_unsigned
internal_sub_unsigned :: proc{internal_int_sub_unsigned}Sourceinternal_submod
internal_submod :: proc{internal_int_submod}Sourceinternal_swap
internal_swap :: proc{internal_int_swap, internal_rat_swap}Sourceinternal_xor
internal_xor :: proc{internal_int_xor}Sourceinternal_zero_unused
internal_zero_unused :: proc{internal_int_zero_unused}Sourceis_even
is_even :: proc{int_is_even, rat_is_even}Sourceis_initialized
is_initialized :: proc{int_is_initialized}Source=== === === === === === === === === === === === === === === === === === === === === === === ===
Comparisons.
See `compare.odin`.
=== === === === === === === === === === === === === === === === === === === === === === === ===is_negative
is_negative :: proc{int_is_negative, rat_is_negative}Sourceis_odd
is_odd :: proc{int_is_odd, rat_is_odd}Sourceis_positive
is_positive :: proc{int_is_positive, rat_is_positive}Sourceis_power_of_two
is_power_of_two :: proc{platform_int_is_power_of_two, int_is_power_of_two}Sourceis_zero
is_zero :: proc{int_is_zero, rat_is_zero}Sourceitoa
itoa :: proc{int_itoa_string, int_itoa_raw}Sourcelcm
lcm :: proc{int_lcm}Sourceless_than
less_than :: proc{int_less_than, int_less_than_digit}Sourceless_than_abs
less_than_abs :: proc{int_less_than_abs}Sourceless_than_or_equal
less_than_or_equal :: proc{int_less_than_or_equal, int_less_than_or_equal_digit}Sourceless_than_or_equal_abs
less_than_or_equal_abs :: proc{int_less_than_or_equal_abs}Sourcelog
log :: proc{int_log, digit_log}Sourceminus_inf
minus_inf :: proc{int_inf}Sourceminus_one
minus_one :: proc{int_minus_one}Sourcemod
mod :: proc{int_mod, int_mod_digit}Sourcemod_bits
mod_bits :: proc{int_mod_bits}Sourcemul
mul :: proc{int_mul, int_mul_digit, rat_mul_rat, rat_mul_int, int_mul_rat}Sourcemulmod
mulmod :: proc{int_mulmod}Sourcenan
nan :: proc{int_nan}Sourceneg
neg :: proc{int_neg, rat_neg}Sourceone
one :: proc{int_one}Sourcepow
pow :: proc{int_pow, int_pow_int, small_pow}Sourcerandom
random :: proc{int_random}Sourcerat_set_frac
rat_set_frac :: proc{rat_set_frac_digit, rat_set_frac_int}Sourceroot_n
root_n :: proc{int_root_n}Sourceset
set :: proc{int_set_from_integer, int_copy, int_atoi, rat_set_f64, rat_set_f32, rat_set_f16, rat_set_u64, rat_set_i64, rat_set_int, rat_set_digit, rat_set_rat}Sourceshl
shl :: proc{int_shl}Sourceshr
shr :: proc{int_shr}Sourceshr_signed
shr_signed :: proc{int_shr_signed}Sourceshrmod
shrmod :: proc{int_shrmod}Sourcesqr
sqr :: proc{int_sqr, rat_sqr}Sourcesqrmod
sqrmod :: proc{int_sqrmod}Sourcesqrt
sqrt :: proc{int_sqrt}Sourcesub
sub :: proc{int_sub, int_sub_digit, rat_sub_rat, rat_sub_int, int_sub_rat}Sourceerr = sub(dest, a, b);
submod
submod :: proc{int_submod}Sourceswap
swap :: proc{int_swap, rat_swap}Source