chiark / gitweb /
Expose inverse() and use it in quadratic3().
authorSimon Tatham <anakin@pobox.com>
Wed, 16 Apr 2025 06:27:33 +0000 (07:27 +0100)
committerSimon Tatham <anakin@pobox.com>
Wed, 16 Apr 2025 18:30:13 +0000 (19:30 +0100)
Silly to compute the same multiplicative inverse twice when we want to
divide both b and c by a. And end users might have the same concern.

src/finite.rs

index a6f43d1b223993781fb0e365ae024b2e5ba1acf8..f430bcd22348e339c9b2bf222932183ff32aecd1 100644 (file)
@@ -4,7 +4,6 @@
 //! top-level module. It's a singleton struct wrapping
 //! [`FiniteNimberEnum`].
 
-use core::cmp::max;
 use core::fmt::{Debug, Display, Formatter};
 use core::ops::{Add, Div, Mul, Neg, Sub};
 use itertools::Itertools;
@@ -971,13 +970,18 @@ impl<'a> FiniteNimberRef<'a> {
             },
         }
     }
+
+    /// Compute the multiplicative inverse of a nimber. Wrapper around
+    /// `inverse_recurse` which also chooses the starting level.
+    fn inverse(&self) -> Option<FiniteNimber> {
+        self.inverse_recurse(self.level())
+    }
 }
 
 impl<'a, 'b> Div<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
     type Output = FiniteNimber;
     fn div(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
-        let level = max(self.level(), other.level());
-        let inverse = other.inverse_recurse(level).expect("Division by zero");
+        let inverse = other.inverse().expect("Division by zero");
         self * inverse.to_ref()
     }
 }
@@ -1138,6 +1142,18 @@ impl FiniteNimber {
         }
     }
 
+    /// Compute the multiplicative inverse of a nimber, i.e. the same
+    /// as `1/x`. Returns an `Option` so that it can return `None` in
+    /// the case of division by zero.
+    ///
+    /// Nimber multiplication is faster than division, so if you're
+    /// dividing more than one nimber by the same value, it's faster
+    /// to compute its inverse once and then multiply all the input
+    /// values by that.
+    pub fn inverse(&self) -> Option<FiniteNimber> {
+        self.to_ref().inverse()
+    }
+
     /// Compute the square of a nimber, just like multiplying it by
     /// itself in the ordinary way. This method is faster than the
     /// general multiplication algorithm performed by the `Mul` trait,
@@ -1285,7 +1301,8 @@ impl FiniteNimber {
     ) -> (FiniteNimber, FiniteNimber) {
         // Strategy: we reduce this to the quadratic2() case by
         // dividing through by a.
-        Self::quadratic2(&(b / a), &(c / a))
+        let ainv = a.inverse().expect("Division by zero");
+        Self::quadratic2(&(b * &ainv), &(c * &ainv))
     }
 }