chiark / gitweb /
Square roots.
authorSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 12:08:19 +0000 (13:08 +0100)
committerSimon Tatham <anakin@pobox.com>
Sat, 12 Apr 2025 12:19:01 +0000 (13:19 +0100)
src/finitenimber.rs

index 6fe1242f08e94574d68aff023eebce068c98bae2..c87fe1bc479c062e18793156ec454079d9cc3a90 100644 (file)
@@ -449,6 +449,34 @@ impl<'a, 'b> Div<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
     }
 }
 
+impl<'a> FiniteNimberRef<'a> {
+    fn sqrt_recurse(self, level: usize) -> FiniteNimber {
+        match level.checked_sub(1) {
+            Some(sublevel) => {
+                let (lo, hi) = self.split(sublevel);
+                let hi_root = hi.sqrt_recurse(sublevel);
+                let sum = hi.mul_by_h(sublevel) + lo;
+                let sum_root = sum.to_ref().sqrt_recurse(sublevel);
+                sum_root.to_ref().join(hi_root.to_ref(), sublevel)
+            }
+
+            // At level 0, both elements of GF(2) square-root to themselves.
+            None => self.into(),
+        }
+    }
+}
+
+impl FiniteNimber {
+    /// Compute the square root of a nimber. Every nimber has a unique
+    /// square root, so this function can't fail, and doesn't need to
+    /// return a list or a tuple or anything more complicated than a
+    /// single nimber.
+    pub fn sqrt(&self) -> FiniteNimber {
+        let r = self.to_ref();
+        r.sqrt_recurse(r.level())
+    }
+}
+
 impl_binop_wrappers!(Add, add, AddAssign, add_assign);
 impl_binop_wrappers!(Sub, sub, SubAssign, sub_assign);
 impl_binop_wrappers!(Mul, mul, MulAssign, mul_assign);
@@ -809,4 +837,37 @@ mod tests {
         // panic.
         let _ = FiniteNimber::from(0x1234) / FiniteNimber::from(0);
     }
+
+    #[test]
+    fn sqrt() {
+        assert_eq!(FiniteNimber::from(0xde).sqrt(), FiniteNimber::from(0x80));
+        assert_eq!(
+            FiniteNimber::from(0xde4a).sqrt(),
+            FiniteNimber::from(0x8000)
+        );
+
+        assert_eq!(
+            FiniteNimber::from(vec![
+                0xd0e74a0945d35342,
+                0xfa91473032b5438a,
+                0xe17bdc047300f99d,
+                0x1a51cba4adb8ddb9,
+                0xdc06e76f54f372c0,
+                0xe74d7b7c65542a19,
+                0xffe69bcb391c628b,
+                0x32ae6e49dcd65156,
+            ])
+            .sqrt(),
+            FiniteNimber::from(vec![
+                0x3f84d5b5b5470917,
+                0xc0ac29b7c97c50dd,
+                0xbe5466cf34e90c6c,
+                0x452821e638d01377,
+                0x082efa98ec4e6c89,
+                0xa4093822299f31d0,
+                0x13198a2e03707344,
+                0x243f6a8885a308d3,
+            ])
+        );
+    }
 }