sub _norm { my($o, @v) = @_; my $a = 1; while ($a) { no warnings qw"uninitialized"; $a = 0; for my $i (keys @v) { if (1 < $v[$i]) { $v[$i] -= 2; $v[$i + 1]++; if (2 <= $i) { $v[$i - 2]++; } elsif (1 <= $i) { $v[0]++; } $a++; } if (0 < $v[$i] && 0 < $v[$i + 1]) { $v[$i]--; $v[$i + 1]--; $v[$i + 2]++; $a++; } } } $o->_make(@v); } sub add { # return the sum of two Zeckendorf objects my($o, $t) = @_; my @v = @$o; my @w = @$t; for my $i (keys @w) { $v[$i] += $w[$i]; } $o->_norm(@v); } sub twice { my($o) = @_; $o->add($o); } our @poweroftwo = (Zeckendorf->one); sub fromnat { # create a Zeckendorf object from a perl natural number my($o, $g) = @_; my $t = 1 + 0 * $g; my $i = 0; my $z = Zeckendorf->zero; while ($t <= $g) { my $y = $poweroftwo[$i] //= $poweroftwo[$i - 1]->twice; if (0 < ($t & $g)) { $z = $z->add($y); } $t <<= 1; $i++; } $z; } }