183 lines
4.7 KiB
Rust
183 lines
4.7 KiB
Rust
struct Zeckendorf {
|
|
d_val: i32,
|
|
d_len: i32,
|
|
}
|
|
|
|
impl Zeckendorf {
|
|
fn new(x: &str) -> Zeckendorf {
|
|
let mut d_val = 0;
|
|
let mut q = 1;
|
|
let mut i = x.len() as i32 - 1;
|
|
let d_len = i / 2;
|
|
while i >= 0 {
|
|
d_val += (x.chars().nth(i as usize).unwrap() as i32 - '0' as i32) * q;
|
|
q *= 2;
|
|
i -= 1;
|
|
}
|
|
|
|
Zeckendorf { d_val, d_len }
|
|
}
|
|
|
|
fn a(&mut self, n: i32) {
|
|
let mut i = n;
|
|
loop {
|
|
if self.d_len < i {
|
|
self.d_len = i;
|
|
}
|
|
let j = (self.d_val >> (i * 2)) & 3;
|
|
match j {
|
|
0 | 1 => return,
|
|
2 => {
|
|
if ((self.d_val >> ((i + 1) * 2)) & 1) != 1 {
|
|
return;
|
|
}
|
|
self.d_val += 1 << (i * 2 + 1);
|
|
return;
|
|
}
|
|
3 => {
|
|
let temp = 3 << (i * 2);
|
|
let temp = !temp;
|
|
self.d_val &= temp;
|
|
self.b((i + 1) * 2);
|
|
}
|
|
_ => (),
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
fn b(&mut self, pos: i32) {
|
|
if pos == 0 {
|
|
self.inc();
|
|
return;
|
|
}
|
|
if ((self.d_val >> pos) & 1) == 0 {
|
|
self.d_val += 1 << pos;
|
|
self.a(pos / 2);
|
|
if pos > 1 {
|
|
self.a(pos / 2 - 1);
|
|
}
|
|
} else {
|
|
let temp = 1 << pos;
|
|
let temp = !temp;
|
|
self.d_val &= temp;
|
|
self.b(pos + 1);
|
|
self.b(pos - if pos > 1 { 2 } else { 1 });
|
|
}
|
|
}
|
|
|
|
fn c(&mut self, pos: i32) {
|
|
if ((self.d_val >> pos) & 1) == 1 {
|
|
let temp = 1 << pos;
|
|
let temp = !temp;
|
|
self.d_val &= temp;
|
|
return;
|
|
}
|
|
self.c(pos + 1);
|
|
if pos > 0 {
|
|
self.b(pos - 1);
|
|
} else {
|
|
self.inc();
|
|
}
|
|
}
|
|
|
|
fn inc(&mut self) -> &mut Self {
|
|
self.d_val += 1;
|
|
self.a(0);
|
|
self
|
|
}
|
|
|
|
fn copy(&self) -> Zeckendorf {
|
|
Zeckendorf {
|
|
d_val: self.d_val,
|
|
d_len: self.d_len,
|
|
}
|
|
}
|
|
|
|
fn plus_assign(&mut self, other: &Zeckendorf) {
|
|
for gn in 0..(other.d_len + 1) * 2 {
|
|
if ((other.d_val >> gn) & 1) == 1 {
|
|
self.b(gn);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn minus_assign(&mut self, other: &Zeckendorf) {
|
|
for gn in 0..(other.d_len + 1) * 2 {
|
|
if ((other.d_val >> gn) & 1) == 1 {
|
|
self.c(gn);
|
|
}
|
|
}
|
|
while (((self.d_val >> self.d_len * 2) & 3) == 0) || (self.d_len == 0) {
|
|
self.d_len -= 1;
|
|
}
|
|
}
|
|
|
|
fn times_assign(&mut self, other: &Zeckendorf) {
|
|
let mut na = other.copy();
|
|
let mut nb = other.copy();
|
|
let mut nt;
|
|
let mut nr = Zeckendorf::new("0");
|
|
for i in 0..(self.d_len + 1) * 2 {
|
|
if ((self.d_val >> i) & 1) > 0 {
|
|
nr.plus_assign(&nb);
|
|
}
|
|
nt = nb.copy();
|
|
nb.plus_assign(&na);
|
|
na = nt.copy(); // `na` is now mutable, so this reassignment is allowed
|
|
}
|
|
self.d_val = nr.d_val;
|
|
self.d_len = nr.d_len;
|
|
}
|
|
|
|
fn to_string(&self) -> String {
|
|
if self.d_val == 0 {
|
|
return "0".to_string();
|
|
}
|
|
|
|
let dig = ["00", "01", "10"];
|
|
let dig1 = ["", "1", "10"];
|
|
|
|
let idx = (self.d_val >> (self.d_len * 2)) & 3;
|
|
let mut sb = String::from(dig1[idx as usize]);
|
|
for i in (0..self.d_len).rev() {
|
|
let idx = (self.d_val >> (i * 2)) & 3;
|
|
sb.push_str(dig[idx as usize]);
|
|
}
|
|
sb
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
println!("Addition:");
|
|
let mut g = Zeckendorf::new("10");
|
|
g.plus_assign(&Zeckendorf::new("10"));
|
|
println!("{}", g.to_string());
|
|
g.plus_assign(&Zeckendorf::new("10"));
|
|
println!("{}", g.to_string());
|
|
g.plus_assign(&Zeckendorf::new("1001"));
|
|
println!("{}", g.to_string());
|
|
g.plus_assign(&Zeckendorf::new("1000"));
|
|
println!("{}", g.to_string());
|
|
g.plus_assign(&Zeckendorf::new("10101"));
|
|
println!("{}", g.to_string());
|
|
println!();
|
|
|
|
println!("Subtraction:");
|
|
g = Zeckendorf::new("1000");
|
|
g.minus_assign(&Zeckendorf::new("101"));
|
|
println!("{}", g.to_string());
|
|
g = Zeckendorf::new("10101010");
|
|
g.minus_assign(&Zeckendorf::new("1010101"));
|
|
println!("{}", g.to_string());
|
|
println!();
|
|
|
|
println!("Multiplication:");
|
|
g = Zeckendorf::new("1001");
|
|
g.times_assign(&Zeckendorf::new("101"));
|
|
println!("{}", g.to_string());
|
|
g = Zeckendorf::new("101010");
|
|
g.plus_assign(&Zeckendorf::new("101"));
|
|
println!("{}", g.to_string());
|
|
}
|