1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
//! 最大公約数と逆元。
/// 最大公約数と逆元。
///
/// 次の条件を満たす唯一の $(g, r)$ を返す。
/// - $g = \\gcd(a, b)$
/// - $a\\cdot r \\equiv g \\pmod{b}$
/// - $0\\le r \\lt b/g$
///
/// $a = 0$ のとき $g = b$ であり、$0\\le g \\lt b$ とはならないことに注意せよ[^1]。
///
/// [^1]: $g = 0$ とすると $b/g$ が定義できないため。
///
/// # Complexity
/// $O(\\log(\\min\\{a, b\\}))$ time.
///
/// # Examples
/// ```
/// use nekolib::math::GcdRecip;
///
/// let (g, r) = 27_u32.gcd_recip(30);
/// assert_eq!(g, 3);
/// assert_eq!(r, 9);
/// assert_eq!((27 * r) % 30, g);
/// ```
pub trait GcdRecip: Sized {
fn gcd_recip(self, other: Self) -> (Self, Self);
}
macro_rules! impl_uint {
($t:ty) => {
impl GcdRecip for $t {
fn gcd_recip(self, other: Self) -> (Self, Self) {
assert!(other > 0);
let a = self % other;
if a == 0 {
return (other, 0);
}
let mut s = other;
let mut t = a;
let mut m0 = 0;
let mut m1 = 1;
while t > 0 {
let u = s / t;
s -= t * u;
// m0 -= m1 * u;
let v = (m1 * u) % other;
m0 = if m0 < v { m0 + other - v } else { m0 - v };
std::mem::swap(&mut s, &mut t);
std::mem::swap(&mut m0, &mut m1);
}
(s, m0 % (other / s))
}
}
};
( $($t:ty)* ) => { $(impl_uint!($t);)* };
}
macro_rules! impl_int {
($t:ty) => {
impl GcdRecip for $t {
fn gcd_recip(self, other: Self) -> (Self, Self) {
assert!(other > 0);
let a = self.rem_euclid(other);
if a == 0 {
return (other, 0);
}
let mut s = other;
let mut t = a;
let mut m0 = 0;
let mut m1 = 1;
while t > 0 {
let u = s / t;
s -= t * u;
m0 -= m1 * u;
std::mem::swap(&mut s, &mut t);
std::mem::swap(&mut m0, &mut m1);
}
if m0 < 0 {
m0 += other / s;
}
(s, m0)
}
}
};
( $($t:ty)* ) => { $(impl_int!($t);)* };
}
impl_uint!(u8 u16 u32 u64 u128 usize);
impl_int!(i8 i16 i32 i64 i128 isize);
#[test]
fn test() {
for b in 1_i32..=1000 {
for a in 0..b {
let (g, r) = a.gcd_recip(b);
assert!(0 <= r && r < b / g);
assert_eq!(a * r % b, g % b);
}
}
for b in 1_u32..=1000 {
for a in 0..b {
let (g, r) = a.gcd_recip(b);
assert!(r < b / g);
assert_eq!(a * r % b, g % b);
}
}
}