}
impl<'a> FiniteNimberRef<'a> {
- fn inverse_recurse(self, level: usize) -> FiniteNimber {
+ fn inverse_recurse(self, level: usize) -> Option<FiniteNimber> {
match level.checked_sub(1) {
Some(sublevel) => {
let (lo, hi) = self.split(sublevel);
let sum = lo + hi;
let sq = hi.square_recurse(sublevel);
let det = lo * sum.to_ref() + sq.to_ref().mul_by_h(sublevel);
- let detinv = det.to_ref().inverse_recurse(sublevel);
- (detinv.to_ref() * sum)
- .to_ref()
- .join((detinv.to_ref() * hi).to_ref(), sublevel)
+ let detinv = det.to_ref().inverse_recurse(sublevel)?;
+ Some(
+ (detinv.to_ref() * sum)
+ .to_ref()
+ .join((detinv.to_ref() * hi).to_ref(), sublevel),
+ )
}
// At level 0, we're in GF(2), so the only invertible
// number is 1, whose inverse is the same as itself.
- //
- // We also map 0 to 0 in the base case. For some
- // applications this makes vague sense (in particular,
- // within a given subfield of order q, raising to the
- // power q-2 is an extension of inversion which maps 0 to
- // 0). The wrapping implementation of the Div trait will
- // check for division by zero.
- None => FiniteNimber::from(self.low_word()),
+ None => match self.low_word() {
+ 0 => None,
+ v => Some(FiniteNimber::from(v)),
+ },
}
}
}
impl<'a, 'b> Div<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
type Output = FiniteNimber;
fn div(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
- // FIXME: how _do_ we check for division by zero?
let level = max(self.level(), other.level());
- self.mul_recurse(other.inverse_recurse(level).to_ref(), level)
+ let inverse = other.inverse_recurse(level).expect("Division by zero");
+ self.mul_recurse(inverse.to_ref(), level)
}
}
])
);
}
+
+ #[test]
+ #[should_panic]
+ fn div0() {
+ // Deliberately divide by zero, and ensure we get the expected
+ // panic.
+ let _ = FiniteNimber::from(0x1234) / FiniteNimber::from(0);
+ }
}