chiark / gitweb /
Handle division by zero
authorSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 12:03:09 +0000 (13:03 +0100)
committerSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 12:18:54 +0000 (13:18 +0100)
src/finitenimber.rs

index 974152aa9e9e8b3334ecd1a96bebf34a82635a11..6fe1242f08e94574d68aff023eebce068c98bae2 100644 (file)
@@ -415,29 +415,27 @@ impl<'a, 'b> Mul<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
 }
 
 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)),
+            },
         }
     }
 }
@@ -445,9 +443,9 @@ impl<'a> FiniteNimberRef<'a> {
 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)
     }
 }
 
@@ -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);
+    }
 }