Zeckendorf arithmetic
This is a somewhat limited implementation of Zeckendorf arithmetic operators. They only handle positive integer values. There are no actual calculations, everything is done with string manipulations, so it doesn't matter what glyphs you use for 1 and 0.
Implemented arithmetic operators:
<b>+z</b> addition
<b>-z</b> subtraction
<b>×z</b> multiplication
<b>/z</b> division (more of a divmod really)
<b>++z</b> post increment
<b>--z</b> post decrementComparison operators:
<b>eqz</b> equal
<b>nez</b> not equal
<b>gtz</b> greater than
<b>ltz</b> less than my $z1 = '1'; # glyph to use for a '1'
my $z0 = '0'; # glyph to use for a '0'
sub zorder($a) { ($z0 lt $z1) ?? $a !! $a.trans([$z0, $z1] => [$z1, $z0]) }
######## Zeckendorf comparison operators #########
# less than
sub infix:<ltz>($a, $b) { $a.&zorder lt $b.&zorder }
# greater than
sub infix:<gtz>($a, $b) { $a.&zorder gt $b.&zorder }
# equal
sub infix:<eqz>($a, $b) { $a eq $b }
# not equal
sub infix:<nez>($a, $b) { $a ne $b }
######## Operators for Zeckendorf arithmetic ########
# post increment
sub postfix:<++z>($a is rw) {
$a = ("$z0$z0"~$a).subst(/("$z0$z0")($z1+ %% $z0)?$/,
-> $/ { "$z0$z1" ~ ($1 ?? $z0 x $1.chars !! '') });
$a ~~ s/^$z0+//;
$a
}
# post decrement
sub postfix:<--z>($a is rw) {
$a.=subst(/$z1($z0*)$/,
-> $/ {$z0 ~ "$z1$z0" x $0.chars div 2 ~ $z1 x $0.chars mod 2});
$a ~~ s/^$z0+(.+)$/$0/;
$a
}
# addition
sub infix:<+z>($a is copy, $b is copy) { $a++z; $a++z while $b--z nez $z0; $a }
# subtraction
sub infix:<-z>($a is copy, $b is copy) { $a--z; $a--z while $b--z nez $z0; $a }
# multiplication
sub infix:<×z>($a, $b) {
return $z0 if $a eqz $z0 or $b eqz $z0;
return $a if $b eqz $z1;
return $b if $a eqz $z1;
my $c = $a;
my $d = $z1;
repeat {
my $e = $z0;
repeat { $c++z; $e++z } until $e eqz $a;
$d++z;
} until $d eqz $b;
$c
}
# division (really more of a div mod)
sub infix:</z>($a is copy, $b is copy) {
fail "Divide by zero" if $b eqz $z0;
return $a if $a eqz $z0 or $b eqz $z1;
my $c = $z0;
repeat {
my $d = $b +z ($z1 ~ $z0);
$c++z;
$a++z;
$a--z while $d--z nez $z0
} until $a ltz $b;
$c ~= " remainder $a" if $a nez $z0;
$c
}
###################### Testing ######################
# helper sub to translate constants into the particular glyphs you used
sub z($a) { $a.trans([<1 0>] => [$z1, $z0]) }
say "Using the glyph '$z1' for 1 and '$z0' for 0\n";
my $fmt = "%-22s = %15s %s\n";
my $zeck = $z1;
printf( $fmt, "$zeck++z", $zeck++z, '# increment' ) for 1 .. 10;
printf $fmt, "$zeck +z {z('1010')}", $zeck +z= z('1010'), '# addition';
printf $fmt, "$zeck -z {z('100')}", $zeck -z= z('100'), '# subtraction';
printf $fmt, "$zeck ×z {z('100101')}", $zeck ×z= z('100101'), '# multiplication';
printf $fmt, "$zeck /z {z('100')}", $zeck /z= z('100'), '# division';
printf( $fmt, "$zeck--z", $zeck--z, '# decrement' ) for 1 .. 5;
printf $fmt, "$zeck ×z {z('101001')}", $zeck ×z= z('101001'), '# multiplication';
printf $fmt, "$zeck /z {z('100')}", $zeck /z= z('100'), '# division';Testing Output
Using alternate glyphs:
Last updated
Was this helpful?