math.big: add get_bit, set_bit, big_mod_pow (#13507)

pull/13508/head
Subhomoy Haldar 2022-02-18 14:23:39 +05:30 committed by GitHub
parent a886242700
commit 072480352c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 142 additions and 0 deletions

View File

@ -262,6 +262,40 @@ fn test_mod_exponentiation() {
assert b.mod_pow(413, div) == a
}
fn test_big_mod_exponentiation_1() {
a := big.integer_from_int(23)
b := big.integer_from_int(35)
c := big.integer_from_int(4205)
result := big.integer_from_int(552)
assert a.big_mod_pow(b, c) == result
}
fn test_big_mod_exponentiation_2() {
a := big.integer_from_string('2222589987119231759186196754430278233855361024') or {
panic('Could not read big integer')
}
b := big.integer_from_string('3104719823194124242') or { panic('Could not read big integer') }
c := big.integer_from_string('15121308410741') or { panic('Could not read big integer') }
result := big.integer_from_string('487881863537') or { panic('Could not read big integer') }
assert a.big_mod_pow(b, c) == result
}
fn test_big_mod_exponentiation_3() {
a := big.integer_from_string('3192874698137469817346981364918346578619384619387463987413') or {
panic('Could not read big integer')
}
b := big.integer_from_string('3104981983749813749137493871037') or {
panic('Could not read big integer')
}
c := big.integer_from_string('2137476918375698711341313') or {
panic('Could not read big integer')
}
result := big.integer_from_string('418107071760838517119254') or {
panic('Could not read big integer')
}
assert a.big_mod_pow(b, c) == result
}
fn test_gcd() {
assert big.integer_from_int(0).gcd(big.integer_from_int(0)) == big.zero_int
assert big.integer_from_int(10).gcd(big.integer_from_int(0)) == big.integer_from_int(10)
@ -362,3 +396,39 @@ fn test_bitwise_ops() {
assert b.bitwise_and(b) == b
assert b.bitwise_not() == big.zero_int
}
fn test_get_bit() {
x := big.integer_from_int(42)
assert x.get_bit(0) == false
assert x.get_bit(1) == true
assert x.get_bit(2) == false
assert x.get_bit(3) == true
assert x.get_bit(4) == false
assert x.get_bit(5) == true
assert x.get_bit(10) == false
values := ['1001001001001010010010100100100101011101001001010',
'1111111111111111111111111111111111111111111111111',
'0000000000000000000000000000000000000000010000', '1110010', '0001001']
for value in values {
a := big.integer_from_radix(value, 2) or { panic('Could not read binary') }
bits := []bool{len: value.len, init: value[value.len - 1 - it] == `1`}
for i in 0 .. value.len {
assert a.get_bit(i) == bits[i]
}
}
}
fn test_set_bit() {
mut a := big.integer_from_int(32)
a.set_bit(1, true)
assert a.int() == 34
a.set_bit(1, false)
a.set_bit(3, true)
assert a.int() == 40
a.set_bit(50, true)
assert a == big.one_int.lshift(50) + big.integer_from_int(40)
b := a
a.set_bit(100, false)
assert a == b
}

View File

@ -425,6 +425,42 @@ pub fn (a Integer) mod_pow(exponent u32, divisor Integer) Integer {
return x * y % divisor
}
pub fn (a Integer) big_mod_pow(exponent Integer, divisor Integer) Integer {
if exponent.signum < 0 {
panic('Exponent needs to be non-negative.')
}
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
}
pub fn (mut a Integer) inc() {
a = a + one_int
}
@ -465,6 +501,42 @@ fn check_sign(a Integer) {
}
}
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
}
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
}
}
pub fn (a Integer) bitwise_or(b Integer) Integer {
check_sign(a)
check_sign(b)