core/math/big

math_big

Types

12

Error

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, }Source

Errors are a strict superset of runtime.Allocation_Error.

Primality_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 }Source

Sign

Sign :: enum u8 { Zero_or_Positive = 0, Negative = 1, }Source

======================= END OF TUNABLES =======================

Constants

59

Error_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 implementSource

_DEFAULT_MUL_KARATSUBA_CUTOFF

_DEFAULT_MUL_KARATSUBA_CUTOFF :: #config(MATH_BIG_MUL_KARATSUBA_CUTOFF, 80)Source

These defaults were tuned on an AMD A8-6600K (64-bit) using libTomMath's make tune.

TODO(Jeroen): Port this tuning algorithm and tune them for more modern processors.

	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.

_FROBENIUS_UNDERWOOD_A

_FROBENIUS_UNDERWOOD_A :: 32764Source

floor 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 a instead, but any a bigger 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.

_MAX_BIT_COUNT

_MAX_BIT_COUNT :: _ = (max(int) - 2)Source

Maximum number of digits.

  • Must be small enough such that _bit_count does not overflow.
  • Must be small enough such that _radix_size for base 2 does not overflow.
`_radix_size` needs two additional bytes for zero termination and sign.

_MIN_DIGIT_COUNT

_MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS)Source

How do we store the Ints?

Minimum number of available digits in `Int`, `_DEFAULT_DIGIT_COUNT` >= `_MIN_DIGIT_COUNT`
	- Must be at least 3 for `_div_school`.
	- Must be large enough such that `init_integer` can store `u128` in the `Int` without growing.

_RADIX_SIZE_SCALE

_RADIX_SIZE_SCALE :: 29Source

Overestimate 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".

Variables

24

_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 `_*`.

Procedures

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)Source

Stores 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)Source

Old internal digit extraction procedure. We're keeping this around as ground truth for the tests.

_private_div_recursion

_private_div_recursion :: proc(quotient: ^Int, remainder: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Direct 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_int_div_school

_private_int_div_school :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Signed 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_dr_reduce

_private_int_dr_reduce :: proc(x: ^Int, n: ^Int, k: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Reduce "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_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)Source

Computes 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_gcd_lcm

_private_int_gcd_lcm :: proc(res_gcd: ^Int, res_lcm: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Internal 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_mul

_private_int_mul :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Multiplies |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_comba

_private_int_mul_comba :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Fast (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_comba

_private_int_mul_high_comba :: proc(dest: ^Int, a: ^Int, b: ^Int, digits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

This 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)Source

product = |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)Source

Multiplication 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_reduce

_private_int_reduce :: proc(x: ^Int, m: ^Int, mu: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Reduces 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_sqr

_private_int_sqr :: proc(dest: ^Int, src: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Low 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)Source

The 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)Source

Karatsuba 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)Source

Squaring 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.

clamp

clamp :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Trim 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.

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_bit_and

int_bit_and :: proc(dest: ^Int, a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Copyright 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_choose_digit

int_choose_digit :: proc(res: ^Int, n: int, k: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Number 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 result

int_clear

int_clear :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Clear Int and resize it to the default size.

int_count_lsb

int_count_lsb :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (count: int, err: Error)Source

Returns the number of trailing zeroes before the first one.

Differs from regular `ctz` in that 0 returns 0.

int_destroy

int_destroy :: proc(integers)Source

TODO: Int.flags and Constants like ONE, NAN, etc, are not yet properly handled everywhere. Deallocates the backing memory of one or more Ints.

int_divmod

int_divmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

divmod.

Both the quotient and remainder are optional and may be passed a nil.

int_get

int_get :: proc(a: ^Int, T: typeid, allocator: mem.Allocator = context.allocator) -> (res: T, err: Error)Source

TODO: Think about using count_bits to check if the value could be returned completely,

and maybe return max(T), .Integer_Overflow if not?

int_inf

int_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Set the Int to Inf and optionally shrink it to the minimum backing size.

int_is_square

int_is_square :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (square: bool, err: Error)Source

Check 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_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)Source

A 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)Source

This version of itoa allocates on behalf of the caller. The caller must free the string.

The radix defaults to 10.

int_minus_inf

int_minus_inf :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Set 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)Source

Set 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)Source

remainder = numerator % denominator.

0 <= remainder < denominator if denominator > 0
	denominator < remainder <= 0 if denominator < 0

int_mul

int_mul :: proc(dest: ^Int, src: ^Int, multiplier: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

High level multiplication (handles sign).

int_nan

int_nan :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Set the Int to NaN and optionally shrink it to the minimum backing size.

int_one

int_one :: proc(a: ^Int, minimize: untyped boolean = false, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Set 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)Source

Calculate dest = base^power using a square-multiply algorithm.

int_root_n

int_root_n :: proc(dest: ^Int, src: ^Int, n: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Find 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_shrmod

int_shrmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, bits: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

quotient, remainder := numerator >> bits;

`remainder` is allowed to be passed a `nil`, in which case `mod` won't be computed.

int_sub

int_sub :: proc(dest: ^Int, number: ^Int, decrease: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

High-level subtraction, dest = number - decrease. Handles signs.

int_swap

int_swap :: proc(a: ^Int, b: ^Int)Source

In 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)Source

Return 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)Source

Return 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)Source

Return 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)Source

Return 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.

internal_clamp

internal_clamp :: proc(a: ^Int) -> (err: Error)Source

Trim 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_int_add_digit

internal_int_add_digit :: proc(dest: ^Int, a: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Low-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_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)Source

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;`

internal_int_divmod

internal_int_divmod :: proc(quotient: ^Int, remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

divmod.

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_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)Source

a 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)Source

Check 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_kronecker

internal_int_kronecker :: proc(a: ^Int, p: ^Int, allocator: mem.Allocator = context.allocator) -> (kronecker: int, err: Error)Source

Kronecker/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_mod

internal_int_mod :: proc(remainder: ^Int, numerator: ^Int, denominator: ^Int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

remainder = 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_pack

internal_int_pack :: proc(a: ^Int, buf: []T, nails: untyped integer = 0, order = Order.LSB_First) -> (written: int, err: Error)Source

Based 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_pow

internal_int_pow :: proc(dest: ^Int, base: ^Int, power: int, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Calculate dest = base^power using a square-multiply algorithm.

Assumes `dest` and `base` 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)Source

This 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_prime_is_divisible

internal_int_prime_is_divisible :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (res: bool, err: Error)Source

Copyright 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)Source

Miller-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_strong_lucas_selfridge

internal_int_prime_strong_lucas_selfridge :: proc(a: ^Int, allocator: mem.Allocator = context.allocator) -> (lucas_selfridge: bool, err: Error)Source

Strong 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_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)Source

We 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)Source

Find 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_sub_digit

internal_int_sub_digit :: proc(dest: ^Int, number: ^Int, digit: DIGIT, allocator: mem.Allocator = context.allocator) -> (err: Error)Source

Low-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)Source

Low-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)Source

Low-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_prime_fermat

internal_prime_fermat :: proc(a: ^Int, b: ^Int, allocator: mem.Allocator = context.allocator) -> (fermat: bool, err: Error)Source

Performs 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)Source

Makes 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!

Procedure Groups

155

add

add :: proc{int_add, int_add_digit, rat_add_rat, rat_add_int, int_add_rat}Source

Copyright 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.

destroy

destroy :: proc{int_destroy, internal_rat_destroy}Source

=== === === === === === === === === === === === === === === === === === === === === === === ===

                              Initialization and other helpers.
	                                    See `helpers.odin`.
	=== === === === === === === === === === === === === === === === === === === === === === === ===

is_initialized

is_initialized :: proc{int_is_initialized}Source

=== === === === === === === === === === === === === === === === === === === === === === === ===

                                        Comparisons.
	                                    See `compare.odin`.
	=== === === === === === === === === === === === === === === === === === === === === === === ===

Reference search

Find anything

Documentation preferences

Settings

System theme variants

Used only while Theme is set to System.