From aa2e9041fe1d6538ee4ad1fe71955562c8132aa4 Mon Sep 17 00:00:00 2001 From: jiyinyiyong Date: Wed, 13 Oct 2021 02:56:48 +0800 Subject: [PATCH] implement buffer interface; tag 0.1.0-a3 --- Cargo.toml | 2 +- README.md | 15 ++++++++ examples/buffer.rs | 13 +++++++ src/digit.rs | 29 ++++++++++++++ src/primes.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++ tests/buffer_test.rs | 32 +++++++++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 examples/buffer.rs create mode 100644 tests/buffer_test.rs diff --git a/Cargo.toml b/Cargo.toml index 298120c..656fe20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dual_balanced_ternary" -version = "0.1.0-a2" +version = "0.1.0-a3" edition = "2018" license = "MIT" description = "Dual Balanced Ternary Arithmetic" diff --git a/README.md b/README.md index dcb8887..24e5d0d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,21 @@ use dual_balanced_ternary::{ternary}; ternary("&1.1") ``` +### Development + +```bash +cargo test +cargo run --example buffer +``` + +Notice, current buffer format is not compact, but conceptually: + +```text +[magic 3]+[integral length]+[integral pairs]+[fractional pairs] +``` + +since a dbt digits pair takes `81` and `u8` takes `256`, `2/3` of spaces are wasted. + ### License MIT diff --git a/examples/buffer.rs b/examples/buffer.rs new file mode 100644 index 0000000..130c02a --- /dev/null +++ b/examples/buffer.rs @@ -0,0 +1,13 @@ +use dual_balanced_ternary::{ternary, DualBalancedTernary}; + +pub fn main() -> Result<(), String> { + println!("{:?}", ternary("&1.1").to_buffer()); + println!("{:?}", ternary("&14.14").to_buffer()); + + println!("{:?}", DualBalancedTernary::from_buffer(vec![3, 1, 21, 21])); + println!("{:?}", DualBalancedTernary::from_buffer(vec![3, 1, 65, 20])); + + println!("TODO {:?}", ternary("&12.12").to_buffer()?); + + Ok(()) +} diff --git a/src/digit.rs b/src/digit.rs index 1be0730..475808a 100644 --- a/src/digit.rs +++ b/src/digit.rs @@ -19,6 +19,35 @@ use DualBalancedTernaryDigit::*; pub type DigitsPair = (DualBalancedTernaryDigit, DualBalancedTernaryDigit); impl DualBalancedTernaryDigit { + pub fn to_u8(&self) -> u8 { + match self { + Dbt1 => 1, + Dbt2 => 2, + Dbt3 => 3, + Dbt4 => 4, + Dbt5 => 5, + Dbt6 => 6, + Dbt7 => 7, + Dbt8 => 8, + Dbt9 => 9, + } + } + + pub fn from_u8(x: u8) -> Result { + match x { + 1 => Ok(Dbt1), + 2 => Ok(Dbt2), + 3 => Ok(Dbt3), + 4 => Ok(Dbt4), + 5 => Ok(Dbt5), + 6 => Ok(Dbt6), + 7 => Ok(Dbt7), + 8 => Ok(Dbt8), + 9 => Ok(Dbt9), + _ => Err(format!("unknown digit for dbt: {}", x)), + } + } + pub fn negate(&self) -> DualBalancedTernaryDigit { match self { Dbt1 => Dbt9, diff --git a/src/primes.rs b/src/primes.rs index bc823ce..91633ac 100644 --- a/src/primes.rs +++ b/src/primes.rs @@ -388,6 +388,98 @@ impl DualBalancedTernary { } result } + + /// buffer format + /// [magic 3]+[integral length]+[integral pairs]+[fractional pairs] + pub fn to_buffer(&self) -> Result, String> { + let int_len = self.integral.len(); + if int_len < 256 { + let mut buf: Vec = vec![3, int_len as u8]; + // for integral part, put space 5 at head + let mut halfed = false; + let mut prev: u8 = 0; + for x in &self.integral { + if halfed { + prev += x.to_u8(); + buf.push(prev.to_owned()); + halfed = false; + } else { + prev = x.to_u8() << 4; + halfed = true; + } + } + if halfed { + prev += 5; + buf.push(prev.to_owned()); + halfed = false; + } + + // expected handled by pair + assert_eq!(buf.len(), ((int_len + 1) >> 1) + 2); + + // for integral part, put space 5 at tail + for x in &self.fractional { + if halfed { + prev += x.to_u8(); + buf.push(prev.to_owned()); + halfed = false; + } else { + prev = x.to_u8() << 4; + halfed = true; + } + } + if halfed { + prev += 5; + buf.push(prev.to_owned()); + } + + Ok(buf) + } else { + Err(format!("integral part too long: {}", int_len)) + } + } + + /// buffer format + /// [magic 3]+[integral length]+[integral pairs]+[fractional pairs] + pub fn from_buffer(buf: Vec) -> Result { + if buf.len() < 2 { + return Err(String::from("dbt buffer expected >=2 u8 numbers")); + } + if buf[0] != 3 { + return Err(String::from("dbt magic number should be 3")); + } + + let int_range = (buf[1] + 1) as usize >> 1; + + if buf.len() < (int_range + 2) { + return Err(String::from("dbt buffer length smaller than integral size")); + } + let mut integral: Vec = vec![]; + let mut fractional: Vec = vec![]; + + // println!("buffer: {:?}", buf); + for (idx, x) in buf.iter().enumerate() { + if idx < 2 { + continue; + } + // println!("reading: {} {}", idx, x); + if idx < (int_range + 2) as usize { + integral.push(DualBalancedTernaryDigit::from_u8((x & 0b11110000) >> 4)?); + integral.push(DualBalancedTernaryDigit::from_u8(x & 0b00001111)?); + } else { + fractional.push(DualBalancedTernaryDigit::from_u8((x & 0b11110000) >> 4)?); + fractional.push(DualBalancedTernaryDigit::from_u8(x & 0b00001111)?); + } + } + + Ok( + Self { + integral, + fractional, + } + .strip_empty_tails(), + ) + } } pub fn parse_ternary_digit(s: char) -> Result { diff --git a/tests/buffer_test.rs b/tests/buffer_test.rs new file mode 100644 index 0000000..6eecae0 --- /dev/null +++ b/tests/buffer_test.rs @@ -0,0 +1,32 @@ +use dual_balanced_ternary::complex::ComplextXy; +use dual_balanced_ternary::{ + create_dual_balanced_ternary_from_pair, ternary, DualBalancedTernary, DualBalancedTernaryDigit::*, +}; + +#[test] +fn to_buffer() -> Result<(), String> { + assert_eq!( + DualBalancedTernary::from_buffer(ternary("&.").to_buffer()?), + Ok(ternary("&.")) + ); + assert_eq!( + DualBalancedTernary::from_buffer(ternary("&1.").to_buffer()?), + Ok(ternary("&1.")) + ); + assert_eq!( + DualBalancedTernary::from_buffer(ternary("&.1").to_buffer()?), + Ok(ternary("&.1")) + ); + + assert_eq!( + DualBalancedTernary::from_buffer(ternary("&12.12").to_buffer()?), + Ok(ternary("&12.12")) + ); + + assert_eq!( + DualBalancedTernary::from_buffer(ternary("&3445647.674").to_buffer()?), + Ok(ternary("&3445647.674")) + ); + + Ok(()) +}