pub trait EquivMod: Sized {
// Required method
fn equiv_mod(self, other: Self) -> Option<Self>;
}
Expand description
Chinese remaindering。
$\gdef{\lcm}{\operatorname{lcm}}$ と に対し、以下を満たす $0\le x\lt\lcm(m_0, m_1)$ を求める。
中国剰余定理から、 であれば常に存在する。 そうでない場合、高々一つ存在する。
なお、計算の利便性のため、$\lcm(m_0, m_1)$ も返す。以下の例も参照。
Idea
として とすると、 左辺は の倍数なので、右辺も の倍数となる必要がある。 よって、 であれば解なしとなる。
以下、 とする。このとき、 は で割り切れ、 となる。 なので は存在する。
これを満たす は一意に定まり、 を計算すればよい。 また、 より、$\lcm(m_0, m_1) = m_0\cdot u_1$ となる。
Examples
use nekolib::math::EquivMod;
assert_eq!((0_i64, 2).equiv_mod((1, 3)), Some((4, 6)));
assert_eq!((0_i64, 2).equiv_mod((1, 4)), None);
イテレータと組み合わせてもよい。 条件 が単位元となることに注意。
use nekolib::math::{EquivMod, Lcm};
let x = (2_i64..=20)
.map(|m| (m - 1, m))
.try_fold((0, 1), |x, y| x.equiv_mod(y));
let lcm = (2_i64..=20).fold(1, |x, y| x.lcm(y));
assert_eq!(x, Some((lcm - 1, lcm)));
簡略版もある。
use nekolib::math::{EquivModIter, Lcm};
let x = (2_i64..=20).map(|m| (m - 1, m)).equiv_mod();
let lcm = (2_i64..=20).fold(1, |x, y| x.lcm(y));
assert_eq!(x, Some((lcm - 1, lcm)));
assert_eq!(std::iter::empty().equiv_mod(), Some((0_i32, 1)));