mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
math.big: minor gcd improvements/fixups and internal rsh_to_set_bit (#18569)
This commit is contained in:
@@ -4,7 +4,6 @@ module big
|
|||||||
for a detailed explanation on these internal functions and the algorithms they
|
for a detailed explanation on these internal functions and the algorithms they
|
||||||
are based on refer to https://github.com/vlang/v/pull/18461
|
are based on refer to https://github.com/vlang/v/pull/18461
|
||||||
*/
|
*/
|
||||||
import math.bits
|
|
||||||
|
|
||||||
// internal struct to make passing montgomery values simpler
|
// internal struct to make passing montgomery values simpler
|
||||||
struct MontgomeryContext {
|
struct MontgomeryContext {
|
||||||
@@ -164,15 +163,8 @@ fn (a Integer) mont_even(x Integer, m Integer) Integer {
|
|||||||
assert !m.is_odd()
|
assert !m.is_odd()
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, get the trailing zeros in m
|
m1, j := m.rsh_to_set_bit()
|
||||||
mut j := u32(0)
|
m2 := one_int.lshift(j)
|
||||||
for m.digits[j] == 0 {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
|
|
||||||
j = j * 32 + u32(bits.trailing_zeros_32(m.digits[j]))
|
|
||||||
|
|
||||||
m1, m2 := m.rshift(j), one_int.lshift(j)
|
|
||||||
|
|
||||||
$if debug {
|
$if debug {
|
||||||
assert m1 * m2 == m
|
assert m1 * m2 == m
|
||||||
|
@@ -939,17 +939,6 @@ fn bi_max(a Integer, b Integer) Integer {
|
|||||||
return if a > b { a } else { b }
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gcd returns the greatest common divisor of the two integers `a` and `b`.
|
// gcd returns the greatest common divisor of the two integers `a` and `b`.
|
||||||
pub fn (a Integer) gcd(b Integer) Integer {
|
pub fn (a Integer) gcd(b Integer) Integer {
|
||||||
if a.signum == 0 {
|
if a.signum == 0 {
|
||||||
@@ -958,51 +947,27 @@ pub fn (a Integer) gcd(b Integer) Integer {
|
|||||||
if b.signum == 0 {
|
if b.signum == 0 {
|
||||||
return a.abs()
|
return a.abs()
|
||||||
}
|
}
|
||||||
if a.signum < 0 {
|
if a.abs_cmp(one_int) == 0 || b.abs_cmp(one_int) == 0 {
|
||||||
return a.neg().gcd(b)
|
return one_int
|
||||||
}
|
|
||||||
if b.signum < 0 {
|
|
||||||
return a.gcd(b.neg())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.digits.len + b.digits.len <= 2 {
|
return gcd_binary(a.abs(), b.abs())
|
||||||
return gcd_euclid(a, b)
|
|
||||||
} else {
|
|
||||||
return gcd_binary(a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspired by the 2013-christmas-special by D. Lemire & R. Corderoy https://en.algorithmica.org/hpc/analyzing-performance/gcd/
|
// 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
|
// 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/
|
// 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 {
|
fn gcd_binary(x Integer, y Integer) Integer {
|
||||||
mut a := x
|
mut a, az := x.rsh_to_set_bit()
|
||||||
mut b := y
|
mut b, bz := y.rsh_to_set_bit()
|
||||||
|
|
||||||
mut az := a.msb()
|
|
||||||
bz := b.msb()
|
|
||||||
shift := umin(az, bz)
|
shift := umin(az, bz)
|
||||||
b = b.rshift(bz)
|
|
||||||
|
|
||||||
for a.signum != 0 {
|
for a.signum != 0 {
|
||||||
a = a.rshift(az)
|
|
||||||
diff := b - a
|
diff := b - a
|
||||||
az = diff.msb()
|
|
||||||
b = bi_min(a, b)
|
b = bi_min(a, b)
|
||||||
a = diff.abs()
|
a, _ = diff.abs().rsh_to_set_bit()
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.lshift(shift)
|
return b.lshift(shift)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,6 +1051,23 @@ fn (a Integer) mod_inv(m Integer) Integer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rsh_to_set_bit returns the integer `x` shifted right until it is odd and an exponent satisfying
|
||||||
|
// `x = x1 * 2^n`
|
||||||
|
// we don't return `2^n`, because the caller may be able to use `n` without allocating an Integer
|
||||||
|
[direct_array_access; inline]
|
||||||
|
fn (x Integer) rsh_to_set_bit() (Integer, u32) {
|
||||||
|
if x.digits.len == 0 {
|
||||||
|
return zero_int, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
mut n := u32(0)
|
||||||
|
for x.digits[n] == 0 {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
n = (n << 5) + u32(bits.trailing_zeros_32(x.digits[n]))
|
||||||
|
return x.rshift(n), n
|
||||||
|
}
|
||||||
|
|
||||||
[direct_array_access; inline]
|
[direct_array_access; inline]
|
||||||
fn (x Integer) is_odd() bool {
|
fn (x Integer) is_odd() bool {
|
||||||
return x.digits[0] & 1 == 1
|
return x.digits[0] & 1 == 1
|
||||||
|
Reference in New Issue
Block a user