From: Simon Tatham Date: Fri, 11 Apr 2025 17:17:34 +0000 (+0100) Subject: mul_by_h working X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=4e16909a245bb3c0ce0c4825ca66655333f20f12;p=nimber.git mul_by_h working --- diff --git a/src/finitenimber.rs b/src/finitenimber.rs index 8577a23..d4dcc33 100644 --- a/src/finitenimber.rs +++ b/src/finitenimber.rs @@ -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); -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 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 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 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> for FiniteNimber { + fn from(n: FiniteNimberRef) -> Self { + FiniteNimber(n.as_slice().into()) + } +} + +impl From for FiniteNimber { + fn from(val: Word) -> FiniteNimber { + FiniteNimber(vec![val]) + } +} + +impl<'a, 'b> Add> 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 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 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 + ]) + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 4f79e4f..bc692dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)); - } -}