math.big: add get_bit, set_bit, big_mod_pow (#13507)
parent
a886242700
commit
072480352c
|
@ -262,6 +262,40 @@ fn test_mod_exponentiation() {
|
||||||
assert b.mod_pow(413, div) == a
|
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() {
|
fn test_gcd() {
|
||||||
assert big.integer_from_int(0).gcd(big.integer_from_int(0)) == big.zero_int
|
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)
|
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_and(b) == b
|
||||||
assert b.bitwise_not() == big.zero_int
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -425,6 +425,42 @@ pub fn (a Integer) mod_pow(exponent u32, divisor Integer) Integer {
|
||||||
return x * y % divisor
|
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() {
|
pub fn (mut a Integer) inc() {
|
||||||
a = a + one_int
|
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 {
|
pub fn (a Integer) bitwise_or(b Integer) Integer {
|
||||||
check_sign(a)
|
check_sign(a)
|
||||||
check_sign(b)
|
check_sign(b)
|
||||||
|
|
Loading…
Reference in New Issue