From: Simon Tatham Date: Sat, 12 Apr 2025 12:03:09 +0000 (+0100) Subject: Handle division by zero X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=d207e771ebac727a07ff96ff676e2af6da8c921c;p=nimber.git Handle division by zero --- diff --git a/src/finitenimber.rs b/src/finitenimber.rs index 974152a..6fe1242 100644 --- a/src/finitenimber.rs +++ b/src/finitenimber.rs @@ -415,29 +415,27 @@ impl<'a, 'b> Mul> for FiniteNimberRef<'b> { } impl<'a> FiniteNimberRef<'a> { - fn inverse_recurse(self, level: usize) -> FiniteNimber { + fn inverse_recurse(self, level: usize) -> Option { 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)), + }, } } } @@ -445,9 +443,9 @@ impl<'a> FiniteNimberRef<'a> { impl<'a, 'b> Div> 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) } } @@ -803,4 +801,12 @@ mod tests { ]) ); } + + #[test] + #[should_panic] + fn div0() { + // Deliberately divide by zero, and ensure we get the expected + // panic. + let _ = FiniteNimber::from(0x1234) / FiniteNimber::from(0); + } }