chiark / gitweb /
mul_by_h working
authorSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 17:17:34 +0000 (18:17 +0100)
committerSimon Tatham <anakin@pobox.com>
Fri, 11 Apr 2025 17:17:34 +0000 (18:17 +0100)
src/finitenimber.rs
src/lib.rs

index 8577a23fd516432a5ae32f0b94aaf07b5690f5c9..d4dcc3348fd5b38cbe205f2e028068c42ee4f24a 100644 (file)
@@ -1,58 +1,48 @@
+use core::fmt::{Debug, Formatter};
 use core::ops::Add;
 
 type Word = u64; // element type of the vectors we use
 const WORDLEVELS: usize = 6; // 2^{2^6} = 64 = size of Word
 
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct FiniteNimber(Vec<Word>);
 
-impl Add<&FiniteNimber> for &FiniteNimber {
-    type Output = FiniteNimber;
-    fn add(self, other: &FiniteNimber) -> FiniteNimber {
-        FiniteNimber(
-            self.0
-                .iter()
-                .zip(other.0.iter())
-                .map(|(a, b)| a ^ b)
-                .collect(),
-        )
-    }
-}
-
-impl Add<&FiniteNimber> for FiniteNimber {
-    type Output = FiniteNimber;
-    fn add(self, other: &FiniteNimber) -> FiniteNimber {
-        (&self) + other
-    }
-}
-
-impl Add<FiniteNimber> for &FiniteNimber {
-    type Output = FiniteNimber;
-    fn add(self, other: FiniteNimber) -> FiniteNimber {
-        self + (&other)
-    }
+#[derive(Clone, Copy)]
+pub enum FiniteNimberRef<'a> {
+    OneWord(Word),
+    Slice(&'a [Word]),
 }
+use FiniteNimberRef::*;
 
-impl Add<FiniteNimber> for FiniteNimber {
-    type Output = FiniteNimber;
-    fn add(self, other: FiniteNimber) -> FiniteNimber {
-        (&self) + (&other)
+impl Debug for FiniteNimber {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
+        write!(f, "FiniteNimber[")?;
+        let mut sep: &str = "";
+        for v in &self.0 {
+            write!(f, "{}0x{:016x}", sep, v)?;
+            sep = ", ";
+        }
+        write!(f, "]")
     }
 }
 
-impl From<Word> for FiniteNimber {
-    fn from(val: Word) -> FiniteNimber {
-        FiniteNimber(vec![val])
+impl Debug for FiniteNimberRef<'_> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
+        match self {
+            OneWord(v) => write!(f, "FiniteNimberRef::OneWord(0x{:16x})", v),
+            Slice(s) => {
+                write!(f, "FiniteNimberRef::Slice[")?;
+                let mut sep: &str = "";
+                for v in *s {
+                    write!(f, "{}0x{:016x}", sep, v)?;
+                    sep = ", ";
+                }
+                write!(f, "]")
+            }
+        }
     }
 }
 
-#[derive(Clone, Copy, Debug)]
-pub enum FiniteNimberRef<'a> {
-    OneWord(Word),
-    Slice(&'a [Word]),
-}
-use FiniteNimberRef::*;
-
 impl<'a> FiniteNimberRef<'a> {
     fn zero() -> Self {
         OneWord(0)
@@ -86,7 +76,7 @@ impl<'a> FiniteNimberRef<'a> {
             None => {
                 // If level < WORDLEVELS then we can cast to Word any old way
                 let bits = 1 << (level as Word);
-                let mask = bits - 1;
+                let mask = (1 << bits) - 1;
                 let v = self.low_word();
                 return (OneWord(v & mask), OneWord((v >> bits) & mask));
             }
@@ -120,7 +110,7 @@ impl<'a> FiniteNimberRef<'a> {
             None => {
                 // If level < WORDLEVELS then we can cast to Word any old way
                 let bits = 1 << (level as Word);
-                let mask = bits - 1;
+                let mask = (1 << bits) - 1;
                 let vlo = self.low_word();
                 let vhi = hi.low_word();
                 ((vlo & mask) | ((vhi & mask) << bits)).into()
@@ -151,11 +141,252 @@ impl<'a> FiniteNimberRef<'a> {
     }
 }
 
+impl FiniteNimber {
+    fn to_ref(&self) -> FiniteNimberRef {
+        match self.0.len() {
+            0 => FiniteNimberRef::zero(),
+            _ => Slice(&self.0),
+        }
+    }
+}
+
 impl<'a> From<&'a FiniteNimber> for FiniteNimberRef<'a> {
     fn from(n: &'a FiniteNimber) -> Self {
-        match n.0.len() {
-            0 => Self::zero(),
-            _ => Slice(&n.0),
+        n.to_ref()
+    }
+}
+
+impl From<FiniteNimberRef<'_>> for FiniteNimber {
+    fn from(n: FiniteNimberRef) -> Self {
+        FiniteNimber(n.as_slice().into())
+    }
+}
+
+impl From<Word> for FiniteNimber {
+    fn from(val: Word) -> FiniteNimber {
+        FiniteNimber(vec![val])
+    }
+}
+
+impl<'a, 'b> Add<FiniteNimberRef<'a>> for FiniteNimberRef<'b> {
+    type Output = FiniteNimber;
+    fn add(self, other: FiniteNimberRef<'a>) -> FiniteNimber {
+        FiniteNimber(
+            self.as_slice()
+                .iter()
+                .zip(other.as_slice().iter())
+                .map(|(a, b)| a ^ b)
+                .collect(),
+        )
+    }
+}
+
+impl Add<&FiniteNimber> for FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: &FiniteNimber) -> FiniteNimber {
+        let aref: FiniteNimberRef = (&self).into();
+        let bref: FiniteNimberRef = other.into();
+        aref + bref
+    }
+}
+
+impl Add<FiniteNimber> for &FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: FiniteNimber) -> FiniteNimber {
+        let aref: FiniteNimberRef = self.into();
+        let bref: FiniteNimberRef = (&other).into();
+        aref + bref
+    }
+}
+
+impl Add<FiniteNimber> for FiniteNimber {
+    type Output = FiniteNimber;
+    fn add(self, other: FiniteNimber) -> FiniteNimber {
+        let aref: FiniteNimberRef = (&self).into();
+        let bref: FiniteNimberRef = (&other).into();
+        aref + bref
+    }
+}
+
+impl<'a> FiniteNimberRef<'a> {
+    fn mul_by_h(self, level: usize) -> FiniteNimber {
+        match level.checked_sub(1) {
+            Some(sublevel) => {
+                let (lo, hi) = self.split(sublevel);
+                hi.mul_by_h(sublevel)
+                    .to_ref()
+                    .mul_by_h(sublevel)
+                    .to_ref()
+                    .join(
+                        (lo + hi).to_ref().mul_by_h(sublevel).to_ref(),
+                        sublevel,
+                    )
+            }
+
+            // At level 0, h = 1, so multiplying by h is a no-op.
+            None => self.into(),
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn split() {
+        let a = FiniteNimber(vec![
+            0x8786858483828180,
+            0x9796959493929190,
+            0xa7a6a5a4a3a2a1a0,
+            0xb7b6b5b4b3b2b1b0,
+            0xc7c6c5c4c3c2c1c0,
+            0xd7d6d5d4d3d2d1d0,
+        ]);
+
+        let (loref, hiref) = a.to_ref().split(4);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![0x8180]));
+        assert_eq!(hi, FiniteNimber(vec![0x8382]));
+
+        let (loref, hiref) = a.to_ref().split(5);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![0x83828180]));
+        assert_eq!(hi, FiniteNimber(vec![0x87868584]));
+
+        let (loref, hiref) = a.to_ref().split(6);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![0x8786858483828180]));
+        assert_eq!(hi, FiniteNimber(vec![0x9796959493929190]));
+
+        let (loref, hiref) = a.to_ref().split(7);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(
+            lo,
+            FiniteNimber(vec![0x8786858483828180, 0x9796959493929190])
+        );
+        assert_eq!(
+            hi,
+            FiniteNimber(vec![0xa7a6a5a4a3a2a1a0, 0xb7b6b5b4b3b2b1b0,])
+        );
+
+        let (loref, hiref) = a.to_ref().split(8);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(
+            lo,
+            FiniteNimber(vec![
+                0x8786858483828180,
+                0x9796959493929190,
+                0xa7a6a5a4a3a2a1a0,
+                0xb7b6b5b4b3b2b1b0
+            ])
+        );
+        assert_eq!(
+            hi,
+            FiniteNimber(vec![0xc7c6c5c4c3c2c1c0, 0xd7d6d5d4d3d2d1d0])
+        );
+
+        let (loref, hiref) = a.to_ref().split(9);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(
+            lo,
+            FiniteNimber(vec![
+                0x8786858483828180,
+                0x9796959493929190,
+                0xa7a6a5a4a3a2a1a0,
+                0xb7b6b5b4b3b2b1b0,
+                0xc7c6c5c4c3c2c1c0,
+                0xd7d6d5d4d3d2d1d0
+            ])
+        );
+        assert_eq!(hi, FiniteNimber(vec![0]));
+
+        let a = FiniteNimber(vec![0xFF]);
+
+        let (loref, hiref) = a.to_ref().split(0);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![1]));
+        assert_eq!(hi, FiniteNimber(vec![1]));
+
+        let (loref, hiref) = a.to_ref().split(1);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![3]));
+        assert_eq!(hi, FiniteNimber(vec![3]));
+
+        let (loref, hiref) = a.to_ref().split(2);
+        let lo: FiniteNimber = loref.into();
+        let hi: FiniteNimber = hiref.into();
+        assert_eq!(lo, FiniteNimber(vec![0xf]));
+        assert_eq!(hi, FiniteNimber(vec![0xf]));
+    }
+
+    #[test]
+    fn join() {
+        let a = FiniteNimber::from(0x5);
+        let b = FiniteNimber::from(0xa);
+        assert_eq!(a.to_ref().join(b.to_ref(), 0), FiniteNimber::from(0b01));
+        assert_eq!(b.to_ref().join(a.to_ref(), 0), FiniteNimber::from(0b10));
+        assert_eq!(a.to_ref().join(b.to_ref(), 1), FiniteNimber::from(0b1001));
+        assert_eq!(b.to_ref().join(a.to_ref(), 1), FiniteNimber::from(0b0110));
+        assert_eq!(a.to_ref().join(b.to_ref(), 2), FiniteNimber::from(0xa5));
+        assert_eq!(b.to_ref().join(a.to_ref(), 2), FiniteNimber::from(0x5a));
+        assert_eq!(
+            a.to_ref().join(b.to_ref(), 5),
+            FiniteNimber::from(0xa00000005)
+        );
+        assert_eq!(
+            a.to_ref().join(b.to_ref(), 6),
+            FiniteNimber(vec![0x5, 0xa])
+        );
+        assert_eq!(
+            a.to_ref().join(b.to_ref(), 8),
+            FiniteNimber(vec![0x5, 0, 0, 0, 0xa])
+        );
+    }
+
+    #[test]
+    fn addition() {
+        let a = FiniteNimber::from(0b1100);
+        let b = FiniteNimber::from(0b1010);
+        assert_eq!(a + b, FiniteNimber::from(0b0110));
+
+        let a = FiniteNimber(vec![1, 1, 0, 0]);
+        let b = FiniteNimber(vec![1, 0, 1, 0]);
+        assert_eq!(a + b, FiniteNimber(vec![0, 1, 1, 0]));
+    }
+
+    #[test]
+    fn mul_by_h() {
+        let a = FiniteNimber::from(1);
+        assert_eq!(a.to_ref().mul_by_h(0), FiniteNimber::from(1));
+        assert_eq!(a.to_ref().mul_by_h(1), FiniteNimber::from(2));
+        assert_eq!(a.to_ref().mul_by_h(2), FiniteNimber::from(8));
+        assert_eq!(a.to_ref().mul_by_h(3), FiniteNimber::from(128));
+        assert_eq!(
+            a.to_ref().mul_by_h(8),
+            FiniteNimber(vec![0, 0, 0, 0x8000000000000000])
+        );
+
+        assert_eq!(
+            a.to_ref().mul_by_h(3).to_ref().mul_by_h(3),
+            FiniteNimber::from(0xde)
+        );
+        assert_eq!(
+            a.to_ref().mul_by_h(8).to_ref().mul_by_h(8),
+            FiniteNimber(vec![
+                0xa92181714b010a1a,
+                0x4a88a921e2208b6b,
+                0xe3a92850a9218171,
+                0xde4ae3a94a88a921
+            ])
+        );
+    }
+}
index 4f79e4fdef35fbe59f54addc76f19636658ab874..bc692dc1f8f71faa90e5998ce3e2ef53bd98e965 100644 (file)
@@ -1,15 +1,3 @@
 mod finitenimber;
 
 pub use finitenimber::FiniteNimber;
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn addition() {
-        let a = FiniteNimber::from(0b1100);
-        let b = FiniteNimber::from(0b1010);
-        assert_eq!(a + b, FiniteNimber::from(0b0110));
-    }
-}