Zeckendorf arithmetic: Difference between revisions

Content added Content deleted
(Added 11l)
Line 2,183: Line 2,183:
1000100
1000100
1000100</pre>
1000100</pre>

=={{header|Perl}}==
<lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Zeckendorf_arithmetic
use warnings;

for ( split /\n/, <<END ) # test cases
1 + 1
10 + 10
10100 + 1010
10100 - 1010
10100 * 1010
100010 * 100101
10100 / 1010
101000 / 1000
100001000001 / 100010
100001000001 / 100101
END
{
my ($left, $op, $right) = split;
my ($x, $y) = map Zeckendorf->new($_), $left, $right;
my $answer =
$op eq '+' ? $x + $y :
$op eq '-' ? $x - $y :
$op eq '*' ? $x * $y :
$op eq '/' ? $x / $y :
die "bad op <$op>";
printf "%12s %s %-9s => %12s in Zeckendorf\n", $x, $op, $y, $answer;
printf "%12d %s %-9d => %12d in decimal\n\n",
$x->asdecimal, $op, $y->asdecimal, $answer->asdecimal;
}

package Zeckendorf;
use overload qw("" zstring + zadd - zsub ++ zinc -- zdec * zmul / zdiv ge zge);

sub new
{
my ($class, $value) = @_;
bless \$value, ref $class || $class;
}

sub zinc
{
my ($self, $other, $swap) = @_;
local $_ = $$self;
s/0$/1/ or s/(?:^|0)1$/10/;
1 while s/(?:^|0)11/100/;
$_[0] = $self->new( s/^0+\B//r );
}

sub zdec
{
my ($self, $other, $swap) = @_;
local $_ = $$self;
1 while s/100(?=0*$)/011/;
s/1$/0/ or s/10$/01/;
$_[0] = $self->new( s/^0+\B//r );
}

sub zstring { ${ shift() } }

sub zadd
{
my ($self, $other, $swap) = @_;
my ($x, $y) = map $self->new($$_), $self, $other; # copy
++$x, $y-- while $$y ne 0;
return $x;
}

sub zsub
{
my ($self, $other, $swap) = @_;
my ($x, $y) = map $self->new($$_), $self, $other; # copy
--$x, $y-- while $$y ne 0;
return $x;
}

sub zmul
{
my ($self, $other, $swap) = @_;
my ($x, $y) = map $self->new($$_), $self, $other; # copy
my $product = Zeckendorf->new(0);
$product = $product + $x, --$y while "$y" ne 0;
return $product;
}

sub zdiv
{
my ($self, $other, $swap) = @_;
my ($x, $y) = map $self->new($$_), $self, $other; # copy
my $quotient = Zeckendorf->new(0);
++$quotient, $x = $x - $y while $x ge $y;
return $quotient;
}

sub zge
{
my ($self, $other, $swap) = @_;
my $l = length( $$self | $$other );
0 x ($l - length $$self) . $$self ge 0 x ($l - length $$other) . $$other;
}

sub asdecimal
{
my ($self) = @_;
my $n = 0;
my $aa = my $bb = 1;
for ( reverse split //, $$self )
{
$n += $bb * $_;
($aa, $bb) = ($bb, $aa + $bb);
}
return $n;
}

sub fromdecimal
{
my ($self, $value) = @_;
my $z = $self->new(0);
++$z for 1 .. $value;
return $z;
}</lang>
{{out}}
<pre>
1 + 1 => 10 in Zeckendorf
1 + 1 => 2 in decimal

10 + 10 => 101 in Zeckendorf
2 + 2 => 4 in decimal

10100 + 1010 => 101000 in Zeckendorf
11 + 7 => 18 in decimal

10100 - 1010 => 101 in Zeckendorf
11 - 7 => 4 in decimal

10100 * 1010 => 101000001 in Zeckendorf
11 * 7 => 77 in decimal

100010 * 100101 => 100001000001 in Zeckendorf
15 * 17 => 255 in decimal

10100 / 1010 => 1 in Zeckendorf
11 / 7 => 1 in decimal

101000 / 1000 => 100 in Zeckendorf
18 / 5 => 3 in decimal

100001000001 / 100010 => 100101 in Zeckendorf
255 / 15 => 17 in decimal

100001000001 / 100101 => 100010 in Zeckendorf
255 / 17 => 15 in decimal

</pre>


=={{header|Phix}}==
=={{header|Phix}}==