2021-08-31 18:21:00 +02:00
module big
2022-01-05 17:02:20 +01:00
import math
2021-08-31 18:21:00 +02:00
import math . bits
import strings
import strconv
const (
digit_array = ' 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z ' . bytes ( )
)
// big.Integer
// -----------
// It has the following properties:
// 1. Every "digit" is an integer in the range [0, 2^32).
// 2. The signum can be one of three values: -1, 0, +1 for
// negative, zero, and positive values, respectively.
// 3. There should be no leading zeros in the digit array.
// 4. The digits are stored in little endian format, that is,
// the digits with a lower positional value (towards the right
// when represented as a string) have a lower index, and vice versa.
pub struct Integer {
digits [ ] u32
pub :
signum int
}
fn int_signum ( value int ) int {
if value == 0 {
return 0
}
return if value < 0 { - 1 } else { 1 }
}
2022-03-30 14:52:09 +02:00
// integer_from_int creates a new `big.Integer` from the given int value.
2021-08-31 18:21:00 +02:00
pub fn integer_from_int ( value int ) Integer {
if value == 0 {
return zero_int
}
return Integer {
2022-01-05 17:02:20 +01:00
digits : [ u32 ( math . abs ( value ) ) ]
2021-08-31 18:21:00 +02:00
signum : int_signum ( value )
}
}
2022-03-30 14:52:09 +02:00
// integer_from_u32 creates a new `big.Integer` from the given u32 value.
2021-08-31 18:21:00 +02:00
pub fn integer_from_u32 ( value u32 ) Integer {
if value == 0 {
return zero_int
}
return Integer {
digits : [ value ]
signum : 1
}
}
2022-03-30 14:52:09 +02:00
// integer_from_i64 creates a new `big.Integer` from the given i64 value.
2021-08-31 18:21:00 +02:00
pub fn integer_from_i64 ( value i64 ) Integer {
if value == 0 {
return zero_int
}
signum_value := if value < 0 { - 1 } else { 1 }
abs_value := u64 ( value * signum_value )
lower := u32 ( abs_value )
upper := u32 ( abs_value >> 32 )
if upper == 0 {
return Integer {
digits : [ lower ]
signum : signum_value
}
} else {
return Integer {
digits : [ lower , upper ]
signum : signum_value
}
}
}
2022-03-30 14:52:09 +02:00
// integer_from_u64 creates a new `big.Integer` from the given u64 value.
2021-08-31 18:21:00 +02:00
pub fn integer_from_u64 ( value u64 ) Integer {
if value == 0 {
return zero_int
}
lower := u32 ( value & 0x00000000ffffffff )
upper := u32 ( ( value & 0xffffffff00000000 ) >> 32 )
if upper == 0 {
return Integer {
digits : [ lower ]
signum : 1
}
} else {
return Integer {
digits : [ lower , upper ]
signum : 1
}
}
}
2021-09-13 23:05:30 +02:00
[ params ]
2021-08-31 18:21:00 +02:00
pub struct IntegerConfig {
signum int = 1
}
2022-03-30 14:52:09 +02:00
// integer_from_bytes creates a new `big.Integer` from the given byte array. By default, positive integers are assumed. If you want a negative integer, use in the following manner:
// `value := big.integer_from_bytes(bytes, signum: -1)`
2022-04-15 14:35:35 +02:00
pub fn integer_from_bytes ( input [ ] u8 , config IntegerConfig ) Integer {
2021-08-31 18:21:00 +02:00
// Thank you to Miccah (@mcastorina) for this implementation and relevant unit tests.
if input . len == 0 {
return integer_from_int ( 0 )
}
// pad input
2022-04-15 14:35:35 +02:00
mut padded_input := [ ] u8 { len : ( ( input . len + 3 ) & ~ 0x3 ) - input . len , cap : ( input . len + 3 ) & ~ 0x3 , init : 0x0 }
2021-08-31 18:21:00 +02:00
padded_input << input
mut digits := [ ] u32 { len : padded_input . len / 4 }
// combine every 4 bytes into a u32 and insert into n.digits
for i := 0 ; i < padded_input . len ; i += 4 {
x3 := u32 ( padded_input [ i ] )
x2 := u32 ( padded_input [ i + 1 ] )
x1 := u32 ( padded_input [ i + 2 ] )
x0 := u32 ( padded_input [ i + 3 ] )
val := ( x3 << 24 ) | ( x2 << 16 ) | ( x1 << 8 ) | x0
digits [ ( padded_input . len - i ) / 4 - 1 ] = val
}
return Integer {
digits : digits
signum : config . signum
}
}
2022-03-30 14:52:09 +02:00
// integer_from_string creates a new `big.Integer` from the decimal digits specified in the given string.
// For other bases, use `big.integer_from_radix` instead.
2021-08-31 18:21:00 +02:00
pub fn integer_from_string ( characters string ) ? Integer {
return integer_from_radix ( characters , 10 )
}
2022-03-30 14:52:09 +02:00
// integer_from_radix creates a new `big.Integer` from the given string and radix.
2021-08-31 18:21:00 +02:00
pub fn integer_from_radix ( all_characters string , radix u32 ) ? Integer {
if radix < 2 || radix > 36 {
return error ( ' R a d i x m u s t b e b e t w e e n 2 a n d 3 6 ( i n c l u s i v e ) ' )
}
characters := all_characters . to_lower ( )
validate_string ( characters , radix ) ?
return match radix {
2 {
integer_from_special_string ( characters , 1 )
}
16 {
integer_from_special_string ( characters , 4 )
}
else {
integer_from_regular_string ( characters , radix )
}
}
}
fn validate_string ( characters string , radix u32 ) ? {
sign_present := characters [ 0 ] == ` + ` || characters [ 0 ] == ` - `
start_index := if sign_present { 1 } else { 0 }
for index := start_index ; index < characters . len ; index ++ {
digit := characters [ index ]
value := big . digit_array . index ( digit )
if value == - 1 {
return error ( ' I n v a l i d c h a r a c t e r $ digit ' )
}
if value >= radix {
return error ( ' I n v a l i d c h a r a c t e r $ digit f o r b a s e $ radix ' )
}
}
}
fn integer_from_special_string ( characters string , chunk_size int ) Integer {
sign_present := characters [ 0 ] == ` + ` || characters [ 0 ] == ` - `
signum := if sign_present {
if characters [ 0 ] == ` - ` { - 1 } else { 1 }
} else {
1
}
start_index := if sign_present { 1 } else { 0 }
mut big_digits := [ ] u32 { cap : ( ( characters . len * chunk_size ) >> 5 ) + 1 }
mut current := u32 ( 0 )
mut offset := 0
for index := characters . len - 1 ; index >= start_index ; index -- {
digit := characters [ index ]
value := u32 ( big . digit_array . index ( digit ) )
current |= value << offset
offset += chunk_size
if offset == 32 {
big_digits << current
current = u32 ( 0 )
offset = 0
}
}
// Store the accumulated value into the digit array
if current != 0 {
big_digits << current
}
for big_digits . len > 0 && big_digits . last ( ) == 0 {
big_digits . delete_last ( )
}
return Integer {
digits : big_digits
signum : if big_digits . len == 0 { 0 } else { signum }
}
}
fn integer_from_regular_string ( characters string , radix u32 ) Integer {
sign_present := characters [ 0 ] == ` + ` || characters [ 0 ] == ` - `
signum := if sign_present {
if characters [ 0 ] == ` - ` { - 1 } else { 1 }
} else {
1
}
start_index := if sign_present { 1 } else { 0 }
mut result := zero_int
radix_int := integer_from_u32 ( radix )
for index := start_index ; index < characters . len ; index ++ {
digit := characters [ index ]
value := big . digit_array . index ( digit )
result *= radix_int
result += integer_from_int ( value )
}
return Integer {
... result
signum : result . signum * signum
}
}
2022-03-30 14:52:09 +02:00
// abs returns the absolute value of the integer.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) abs ( ) Integer {
return if integer . signum == 0 {
zero_int
} else {
Integer {
... integer
signum : 1
}
}
}
2022-03-30 14:52:09 +02:00
// neg returns the result of negation of the integer.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) neg ( ) Integer {
return if integer . signum == 0 {
zero_int
} else {
Integer {
... integer
signum : - integer . signum
}
}
}
pub fn ( integer Integer ) + ( addend Integer ) Integer {
// Quick exits
if integer . signum == 0 {
return addend
}
if addend . signum == 0 {
return integer
}
// Non-zero cases
return if integer . signum == addend . signum {
integer . add ( addend )
} else { // Unequal signs
integer . subtract ( addend )
}
}
pub fn ( integer Integer ) - ( subtrahend Integer ) Integer {
// Quick exits
if integer . signum == 0 {
return subtrahend . neg ( )
}
if subtrahend . signum == 0 {
return integer
}
// Non-zero cases
return if integer . signum == subtrahend . signum {
integer . subtract ( subtrahend )
} else {
integer . add ( subtrahend )
}
}
fn ( integer Integer ) add ( addend Integer ) Integer {
a := integer . digits
b := addend . digits
2022-01-05 17:02:20 +01:00
mut storage := [ ] u32 { len : math . max ( a . len , b . len ) + 1 }
2021-08-31 18:21:00 +02:00
add_digit_array ( a , b , mut storage )
return Integer {
... integer
digits : storage
}
}
fn ( integer Integer ) subtract ( subtrahend Integer ) Integer {
cmp := integer . abs_cmp ( subtrahend )
if cmp == 0 {
return zero_int
}
a , b := if cmp > 0 { integer , subtrahend } else { subtrahend , integer }
mut storage := [ ] u32 { len : a . digits . len }
subtract_digit_array ( a . digits , b . digits , mut storage )
return Integer {
signum : cmp * a . signum
digits : storage
}
}
pub fn ( integer Integer ) * ( multiplicand Integer ) Integer {
// Quick exits
if integer . signum == 0 || multiplicand . signum == 0 {
return zero_int
}
if integer == one_int {
return multiplicand
}
if multiplicand == one_int {
return integer
}
// The final sign is the product of the signs
mut storage := [ ] u32 { len : integer . digits . len + multiplicand . digits . len }
multiply_digit_array ( integer . digits , multiplicand . digits , mut storage )
return Integer {
signum : integer . signum * multiplicand . signum
digits : storage
}
}
2022-03-30 14:52:09 +02:00
// div_mod returns the quotient and remainder of the integer division.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) div_mod ( divisor Integer ) ( Integer , Integer ) {
// Quick exits
if divisor . signum == 0 {
panic ( ' C a n n o t d i v i d e b y z e r o ' )
}
if integer . signum == 0 {
return zero_int , zero_int
}
if divisor == one_int {
return integer , zero_int
}
if divisor . signum == - 1 {
q , r := integer . div_mod ( divisor . neg ( ) )
return q . neg ( ) , r
}
if integer . signum == - 1 {
q , r := integer . neg ( ) . div_mod ( divisor )
if r . signum == 0 {
return q . neg ( ) , zero_int
} else {
return q . neg ( ) - one_int , divisor - r
}
}
// Division for positive integers
mut q := [ ] u32 { cap : integer . digits . len - divisor . digits . len + 1 }
mut r := [ ] u32 { cap : integer . digits . len }
divide_digit_array ( integer . digits , divisor . digits , mut q , mut r )
quotient := Integer {
signum : if q . len == 0 { 0 } else { 1 }
digits : q
}
remainder := Integer {
signum : if r . len == 0 { 0 } else { 1 }
digits : r
}
return quotient , remainder
}
pub fn ( a Integer ) / ( b Integer ) Integer {
q , _ := a . div_mod ( b )
return q
}
pub fn ( a Integer ) % ( b Integer ) Integer {
_ , r := a . div_mod ( b )
return r
}
2022-03-30 14:52:09 +02:00
// pow returns the integer `a` raised to the power of the u32 `exponent`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) pow ( exponent u32 ) Integer {
if exponent == 0 {
return one_int
}
if exponent == 1 {
return a
}
mut n := exponent
mut x := a
mut y := one_int
for n > 1 {
if n & 1 == 1 {
y *= x
}
x *= x
n >>= 1
}
return x * y
}
2022-03-30 14:52:09 +02:00
// mod_pow returns the integer `a` raised to the power of the u32 `exponent` modulo the integer `divisor`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) mod_pow ( exponent u32 , divisor Integer ) Integer {
if exponent == 0 {
return one_int
}
if exponent == 1 {
return a % divisor
}
mut n := exponent
mut x := a % divisor
mut y := one_int
for n > 1 {
if n & 1 == 1 {
y *= x % divisor
}
x *= x % divisor
n >>= 1
}
return x * y % divisor
}
2022-03-30 14:52:09 +02:00
// big_mod_power returns the integer `a` raised to the power of the integer `exponent` modulo the integer `divisor`.
2022-02-18 09:53:39 +01:00
pub fn ( a Integer ) big_mod_pow ( exponent Integer , divisor Integer ) Integer {
if exponent . signum < 0 {
panic ( ' E x p o n e n t n e e d s t o b e n o n - n e g a t i v e . ' )
}
if exponent . signum == 0 {
return one_int
}
mut x := a % divisor
mut y := one_int
mut n := u32 ( 0 )
// For all but the last digit of the exponent
for index in 0 .. exponent . digits . len - 1 {
n = exponent . digits [ index ]
for _ in 0 .. 32 {
if n & 1 == 1 {
y *= x % divisor
}
x *= x % divisor
n >>= 1
}
}
// Last digit of the exponent
n = exponent . digits . last ( )
for n > 1 {
if n & 1 == 1 {
y *= x % divisor
}
x *= x % divisor
n >>= 1
}
return x * y % divisor
}
2022-03-30 14:52:09 +02:00
// inc returns the integer `a` incremented by 1.
2021-08-31 18:21:00 +02:00
pub fn ( mut a Integer ) inc ( ) {
a = a + one_int
}
2022-03-30 14:52:09 +02:00
// dec returns the integer `a` decremented by 1.
2021-08-31 18:21:00 +02:00
pub fn ( mut a Integer ) dec ( ) {
a = a - one_int
}
pub fn ( a Integer ) == ( b Integer ) bool {
return a . signum == b . signum && a . digits . len == b . digits . len && a . digits == b . digits
}
2022-03-30 14:52:09 +02:00
// abs_cmp returns the result of comparing the magnitudes of the integers `a` and `b`.
// It returns a negative int if `|a| < |b|`, 0 if `|a| == |b|`, and a positive int if `|a| > |b|`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) abs_cmp ( b Integer ) int {
return compare_digit_array ( a . digits , b . digits )
}
pub fn ( a Integer ) < ( b Integer ) bool {
// Quick exits based on signum value:
if a . signum < b . signum {
return true
}
if a . signum > b . signum {
return false
}
// They have equal sign
signum := a . signum
if signum == 0 { // Are they both zero?
return false
}
// If they are negative, the one with the larger absolute value is smaller
2021-09-08 19:30:20 +02:00
cmp := a . abs_cmp ( b )
2021-08-31 18:21:00 +02:00
return if signum < 0 { cmp > 0 } else { cmp < 0 }
}
fn check_sign ( a Integer ) {
if a . signum < 0 {
panic ( ' B i t w i s e o p e r a t i o n s a r e o n l y s u p p o r t e d f o r n o n n e g a t i v e i n t e g e r s ' )
}
}
2022-03-30 14:52:09 +02:00
// get_bit checks whether the bit at the given index is set.
2022-02-18 09:53:39 +01:00
pub fn ( a Integer ) get_bit ( i u32 ) bool {
check_sign ( a )
target_index := i / 32
offset := i % 32
if target_index >= a . digits . len {
return false
}
return ( a . digits [ target_index ] >> offset ) & 1 != 0
}
2022-03-30 14:52:09 +02:00
// set_bit sets the bit at the given index to the given value.
2022-02-18 09:53:39 +01:00
pub fn ( mut a Integer ) set_bit ( i u32 , value bool ) {
check_sign ( a )
target_index := i / 32
offset := i % 32
if target_index >= a . digits . len {
if value {
a = one_int . lshift ( i ) . bitwise_or ( a )
}
return
}
mut copy := a . digits . clone ( )
if value {
copy [ target_index ] |= 1 << offset
} else {
copy [ target_index ] &= ~ ( 1 << offset )
}
a = Integer {
signum : a . signum
digits : copy
}
}
2022-03-30 14:52:09 +02:00
// bitwise_or returns the "bitwise or" of the integers `a` and `b`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) bitwise_or ( b Integer ) Integer {
check_sign ( a )
check_sign ( b )
2022-01-05 17:02:20 +01:00
mut result := [ ] u32 { len : math . max ( a . digits . len , b . digits . len ) , init : 0 }
2021-08-31 18:21:00 +02:00
bitwise_or_digit_array ( a . digits , b . digits , mut result )
return Integer {
digits : result
signum : if result . len == 0 { 0 } else { 1 }
}
}
2022-03-30 14:52:09 +02:00
// bitwise_and returns the "bitwise and" of the integers `a` and `b`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) bitwise_and ( b Integer ) Integer {
check_sign ( a )
check_sign ( b )
2022-01-05 17:02:20 +01:00
mut result := [ ] u32 { len : math . max ( a . digits . len , b . digits . len ) , init : 0 }
2021-08-31 18:21:00 +02:00
bitwise_and_digit_array ( a . digits , b . digits , mut result )
return Integer {
digits : result
signum : if result . len == 0 { 0 } else { 1 }
}
}
2022-03-30 14:52:09 +02:00
// bitwise_not returns the "bitwise not" of the integer `a`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) bitwise_not ( ) Integer {
check_sign ( a )
mut result := [ ] u32 { len : a . digits . len , init : 0 }
bitwise_not_digit_array ( a . digits , mut result )
return Integer {
digits : result
signum : if result . len == 0 { 0 } else { 1 }
}
}
2022-03-30 14:52:09 +02:00
// bitwise_xor returns the "bitwise exclusive or" of the integers `a` and `b`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) bitwise_xor ( b Integer ) Integer {
check_sign ( a )
check_sign ( b )
2022-01-05 17:02:20 +01:00
mut result := [ ] u32 { len : math . max ( a . digits . len , b . digits . len ) , init : 0 }
2021-08-31 18:21:00 +02:00
bitwise_xor_digit_array ( a . digits , b . digits , mut result )
return Integer {
digits : result
signum : if result . len == 0 { 0 } else { 1 }
}
}
2022-03-30 14:52:09 +02:00
// lshift returns the integer `a` shifted left by `amount` bits.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) lshift ( amount u32 ) Integer {
if a . signum == 0 {
return a
}
if amount == 0 {
return a
}
normalised_amount := amount & 31
digit_offset := int ( amount >> 5 )
mut new_array := [ ] u32 { len : a . digits . len + digit_offset , init : 0 }
for index in 0 .. a . digits . len {
new_array [ index + digit_offset ] = a . digits [ index ]
}
if normalised_amount > 0 {
shift_digits_left ( new_array , normalised_amount , mut new_array )
}
return Integer {
digits : new_array
signum : a . signum
}
}
2022-03-30 14:52:09 +02:00
// rshift returns the integer `a` shifted right by `amount` bits.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) rshift ( amount u32 ) Integer {
if a . signum == 0 {
return a
}
if amount == 0 {
return a
}
normalised_amount := amount & 31
digit_offset := int ( amount >> 5 )
if digit_offset >= a . digits . len {
return zero_int
}
mut new_array := [ ] u32 { len : a . digits . len - digit_offset , init : 0 }
for index in 0 .. new_array . len {
new_array [ index ] = a . digits [ index + digit_offset ]
}
if normalised_amount > 0 {
shift_digits_right ( new_array , normalised_amount , mut new_array )
}
return Integer {
digits : new_array
signum : a . signum
}
}
2022-03-30 14:52:09 +02:00
// binary_str returns the binary string representation of the integer `a`.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) binary_str ( ) string {
// We have the zero integer
if integer . signum == 0 {
return ' 0 '
}
// Add the sign if present
sign_needed := integer . signum == - 1
2022-03-30 14:52:09 +02:00
mut result_builder := strings . new_builder ( integer . bit_len ( ) + if sign_needed { 1 } else { 0 } )
2021-08-31 18:21:00 +02:00
if sign_needed {
result_builder . write_string ( ' - ' )
}
result_builder . write_string ( u32_to_binary_without_lz ( integer . digits [ integer . digits . len - 1 ] ) )
for index := integer . digits . len - 2 ; index >= 0 ; index -- {
result_builder . write_string ( u32_to_binary_with_lz ( integer . digits [ index ] ) )
}
return result_builder . str ( )
}
2022-03-30 14:52:09 +02:00
// hex returns the hexadecimal string representation of the integer `a`.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) hex ( ) string {
// We have the zero integer
if integer . signum == 0 {
return ' 0 '
}
// Add the sign if present
sign_needed := integer . signum == - 1
mut result_builder := strings . new_builder ( integer . digits . len * 8 +
if sign_needed { 1 } else { 0 } )
if sign_needed {
result_builder . write_string ( ' - ' )
}
result_builder . write_string ( u32_to_hex_without_lz ( integer . digits [ integer . digits . len - 1 ] ) )
for index := integer . digits . len - 2 ; index >= 0 ; index -- {
result_builder . write_string ( u32_to_hex_with_lz ( integer . digits [ index ] ) )
}
return result_builder . str ( )
}
2022-03-30 14:52:09 +02:00
// radix_str returns the string representation of the integer `a` in the specified radix.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) radix_str ( radix u32 ) string {
if integer . signum == 0 {
return ' 0 '
}
return match radix {
2 {
integer . binary_str ( )
}
16 {
integer . hex ( )
}
else {
integer . general_radix_str ( radix )
}
}
}
fn ( integer Integer ) general_radix_str ( radix u32 ) string {
divisor := integer_from_u32 ( radix )
mut rune_array := [ ] rune { }
mut current := integer . abs ( )
mut digit := zero_int
for current . signum > 0 {
current , digit = current . div_mod ( divisor )
rune_array << big . digit_array [ digit . int ( ) ]
}
if integer . signum == - 1 {
rune_array << ` - `
}
rune_array . reverse_in_place ( )
return rune_array . string ( )
}
2022-03-30 14:52:09 +02:00
// str returns the decimal string representation of the integer `a`.
2021-08-31 18:21:00 +02:00
pub fn ( integer Integer ) str ( ) string {
return integer . radix_str ( 10 )
}
fn u32_to_binary_without_lz ( value u32 ) string {
return strconv . format_uint ( value , 2 )
}
fn u32_to_binary_with_lz ( value u32 ) string {
mut result_builder := strings . new_builder ( 32 )
binary_result := strconv . format_uint ( value , 2 )
result_builder . write_string ( strings . repeat ( ` 0 ` , 32 - binary_result . len ) )
result_builder . write_string ( binary_result )
return result_builder . str ( )
}
fn u32_to_hex_without_lz ( value u32 ) string {
return strconv . format_uint ( value , 16 )
}
fn u32_to_hex_with_lz ( value u32 ) string {
mut result_builder := strings . new_builder ( 8 )
hex_result := strconv . format_uint ( value , 16 )
result_builder . write_string ( strings . repeat ( ` 0 ` , 8 - hex_result . len ) )
result_builder . write_string ( hex_result )
return result_builder . str ( )
}
2022-03-30 14:52:09 +02:00
// int returns the integer value of the integer `a`.
// NOTE: This may cause loss of precision.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) int ( ) int {
if a . signum == 0 {
return 0
}
value := int ( a . digits [ 0 ] & 0x7fffffff )
return value * a . signum
}
2022-03-30 14:52:09 +02:00
// bytes returns the a byte representation of the integer a, along with the signum int.
// NOTE: The byte array returned is in big endian order.
2022-04-15 14:35:35 +02:00
pub fn ( a Integer ) bytes ( ) ( [ ] u8 , int ) {
2021-08-31 18:21:00 +02:00
if a . signum == 0 {
2022-04-15 14:35:35 +02:00
return [ ] u8 { len : 0 } , 0
2021-08-31 18:21:00 +02:00
}
2022-04-15 14:35:35 +02:00
mut result := [ ] u8 { cap : a . digits . len * 4 }
2021-08-31 18:21:00 +02:00
mut mask := u32 ( 0xff000000 )
mut offset := 24
mut non_zero_found := false
for index := a . digits . len - 1 ; index >= 0 ; {
2022-04-15 13:58:56 +02:00
value := u8 ( ( a . digits [ index ] & mask ) >> offset )
2021-08-31 18:21:00 +02:00
non_zero_found = non_zero_found || value != 0
if non_zero_found {
result << value
}
mask >>= 8
offset -= 8
if offset < 0 {
mask = u32 ( 0xff000000 )
offset = 24
index --
}
}
return result , a . signum
}
2022-03-30 14:52:09 +02:00
// factorial returns the factorial of the integer `a`.
2021-08-31 18:21:00 +02:00
pub fn ( a Integer ) factorial ( ) Integer {
if a . signum == 0 {
return one_int
}
mut product := one_int
mut current := a
for current . signum != 0 {
product *= current
current . dec ( )
}
return product
}
// isqrt returns the closest integer square root of the given integer.
pub fn ( a Integer ) isqrt ( ) Integer {
if a . signum < 0 {
panic ( ' C a n n o t o b t a i n s q u a r e r o o t o f n e g a t i v e i n t e g e r ' )
}
if a . signum == 0 {
return a
}
if a . digits . len == 1 && a . digits . last ( ) == 1 {
return a
}
2022-03-30 14:52:09 +02:00
mut shift := a . bit_len ( )
2021-08-31 18:21:00 +02:00
if shift & 1 == 1 {
shift += 1
}
mut result := zero_int
for shift >= 0 {
result = result . lshift ( 1 )
larger := result + one_int
if ( larger * larger ) . abs_cmp ( a . rshift ( u32 ( shift ) ) ) <= 0 {
result = larger
}
shift -= 2
}
return result
}
2021-10-26 10:10:13 +02:00
[ inline ]
fn bi_min ( a Integer , b Integer ) Integer {
return if a < b { a } else { b }
}
[ inline ]
fn bi_max ( a Integer , b Integer ) Integer {
return if a > b { a } else { b }
}
[ direct_array_access ]
fn ( bi Integer ) msb ( ) u32 {
for idx := 0 ; idx < bi . digits . len ; idx += 1 {
word := bi . digits [ idx ]
if word > 0 {
return u32 ( ( idx * 32 ) + bits . trailing_zeros_32 ( word ) )
}
}
return u32 ( 32 )
}
2022-03-30 14:52:09 +02:00
// gcd returns the greatest common divisor of the two integers `a` and `b`.
pub fn ( a Integer ) gcd ( b Integer ) Integer {
if a . signum == 0 {
return b . abs ( )
}
if b . signum == 0 {
return a . abs ( )
}
if a . signum < 0 {
return a . neg ( ) . gcd ( b )
2021-10-26 10:10:13 +02:00
}
2022-03-30 14:52:09 +02:00
if b . signum < 0 {
return a . gcd ( b . neg ( ) )
2021-10-26 10:10:13 +02:00
}
2022-03-30 14:52:09 +02:00
if a . digits . len + b . digits . len <= 2 {
return gcd_euclid ( a , b )
} else {
return gcd_binary ( a , b )
2021-10-26 10:10:13 +02:00
}
2022-03-30 14:52:09 +02:00
}
fn gcd_euclid ( x Integer , y Integer ) Integer {
mut a := x
mut b := y
mut r := a % b
for r . signum != 0 {
a = b
b = r
r = a % b
2021-10-26 10:10:13 +02:00
}
2022-03-30 14:52:09 +02:00
return b
}
2021-10-26 10:10:13 +02:00
2022-03-30 14:52:09 +02:00
// Inspired by the 2013-christmas-special by D. Lemire & R. Corderoy https://en.algorithmica.org/hpc/analyzing-performance/gcd/
// For more information, refer to the Wikipedia article: https://en.wikipedia.org/wiki/Binary_GCD_algorithm
// Discussion and further information: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor/
fn gcd_binary ( x Integer , y Integer ) Integer {
2021-10-26 10:10:13 +02:00
mut a := x
mut b := y
mut az := a . msb ( )
bz := b . msb ( )
2022-01-05 17:02:20 +01:00
shift := math . min ( az , bz )
2021-10-26 10:10:13 +02:00
b = b . rshift ( bz )
for a . signum != 0 {
a = a . rshift ( az )
diff := b - a
az = diff . msb ( )
b = bi_min ( a , b )
a = diff . abs ( )
}
return b . lshift ( shift )
}
2022-03-30 14:52:09 +02:00
// bit_len returns the number of bits required to represent the integer `a`.
[ direct_array_access ; inline ]
pub fn ( x Integer ) bit_len ( ) int {
if x . signum == 0 {
return 0
}
return x . digits . len * 32 - bits . leading_zeros_32 ( x . digits . last ( ) )
}