None => self.into(),
}
}
+}
+
+impl<'a, 'b> Mul<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
+ type Output = FiniteNimber;
/// Recursively multiply two nimbers. Underlies the [`Mul`]
/// implementations on `FiniteNimber` itself.
///
- /// The most obvious formula for multiplying a = ah\*t+al by b =
- /// bh\*t+bl is
+ /// If the two input nimbers have the same level, that's the
+ /// interesting case. The most obvious formula for multiplying a =
+ /// ah\*t+al by b = bh\*t+bl is
///
/// ```text
/// (ah t + al)(bh t + bl)
/// ```text
/// (k + al bl) t + (ah bh h + al bl)
/// ```
- fn mul_recurse(
- self,
- other: FiniteNimberRef<'a>,
- level: usize,
- ) -> FiniteNimber {
- match level.checked_sub(1) {
- Some(sublevel) => {
- let (alo, ahi) = self.split(sublevel);
- let (blo, bhi) = other.split(sublevel);
- let karatsuba = (alo + ahi) * (blo + bhi);
- let albl = alo * blo;
- let ahbh = ahi * bhi;
- (&albl + ahbh.to_ref().mul_by_h(sublevel))
- .to_ref()
- .join((karatsuba + &albl).to_ref(), sublevel)
- }
+ ///
+ /// However, if we're given two nimbers to multiply _not_ at the
+ /// same level, we can do something much easier: only split up the
+ /// larger nimber (say b), and simply multiply each of its halves
+ /// by the smaller one in the obvious way:
+ ///
+ /// ```text
+ /// a(bh t + bl)
+ /// = (a bh) t + (a bl)
+ /// ```
+ fn mul(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
+ let slevel = self.level();
+ let olevel = other.level();
- // At level 0, we're in GF(2), so multiplication looks
- // like bitwise AND.
- None => FiniteNimber::from(self.low_word() & other.low_word()),
- }
- }
-}
+ // Sort the two inputs so that alevel <= blevel
+ let (a, b, alevel, blevel) = if slevel > olevel {
+ (other, self, olevel, slevel)
+ } else {
+ (self, other, slevel, olevel)
+ };
-impl<'a, 'b> Mul<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
- type Output = FiniteNimber;
- fn mul(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
- let level = max(self.level(), other.level());
- self.mul_recurse(other, level)
+ if alevel < blevel {
+ // The easy case, where we only need to split up b and
+ // recurse twice to the next level down.
+ let sublevel = blevel - 1;
+ let (blo, bhi) = b.split(sublevel);
+ (blo * a).to_ref().join((bhi * a).to_ref(), sublevel)
+ } else {
+ // The hard case, where we must split up both nimbers and
+ // do three full recursive multiplications plus a mul_by_h.
+ match alevel.checked_sub(1) {
+ Some(sublevel) => {
+ let (alo, ahi) = a.split(sublevel);
+ let (blo, bhi) = b.split(sublevel);
+ let karatsuba = (alo + ahi) * (blo + bhi);
+ let albl = alo * blo;
+ let ahbh = ahi * bhi;
+ (&albl + ahbh.to_ref().mul_by_h(sublevel))
+ .to_ref()
+ .join((karatsuba + &albl).to_ref(), sublevel)
+ }
+
+ // At level 0, we're in GF(2), so multiplication looks
+ // like bitwise AND.
+ None => FiniteNimber::from(a.low_word() & b.low_word()),
+ }
+ }
}
}
fn div(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
let level = max(self.level(), other.level());
let inverse = other.inverse_recurse(level).expect("Division by zero");
- self.mul_recurse(inverse.to_ref(), level)
+ self * inverse.to_ref()
}
}