- package divisors;
-
- sub new {
- my $c = shift;
- my $s = {
- _sieve => {2=>1, 3=>1},
- _high => 3
- };
-
- bless $s, $c;
- return $s;
- }
-
- sub make_sieve {
- my ($s, $limit) = @_;
- my %sieve = (2=>1, 3=>1);
- my $k, $x, $y, $root;
-
- $k = 2;
- $root = int sqrt $limit;
-
- for $x (1..$root) {
- for $y (1..$root) {
- $n = 4*$x**2 + $y**2;
- $sieve{$n} = !defined($sieve{$n}) || !$sieve{$n} if $n <= $limit && ($n%12==1 || $n%12==5);
-
- $n = 3*$x**2+$y**2;
- $sieve{$n} = !defined($sieve{$n}) || !$sieve{$n} if $n <= $limit && $n%12==7;
-
- $n = 3*$x**2-$y**2;
- $sieve{$n} = !defined($sieve{$n}) || !$sieve{$n} if ($n <= $limit && $x > $y && $n%12==11);
- }
- }
-
- for $x (5..$root) {
- $sieve{$x} = 0 if ! defined $sieve{$x};
-
- if ($sieve{$x}) {
- for $k (1..$k*$x**2) {
- $sieve{$k*$x**2} = 0;
- }
- }
- }
-
- for $x (grep {$sieve{$_}} keys %sieve) {
- $s->{_sieve}->{$x} = 1;
- }
-
- $s->{_high} = $limit;
- }
-
- sub get_primes {
- my ($s, $limit) = @_;
-
- my @primes = grep { $_ < $limit } keys %{$s->{_sieve}};
- return sort { $a <=> $b } @primes;
- }
-
- sub factor {
- my ($s, $n, @rest) = @_;
- $n = - $n if $n < 0;
- my $k;
- my $factors = {};
-
- return 0 if $n < 1;
-
- $s->make_sieve($n) if $n > $s->{_high};
-
-
- for $k (grep { $_ < $n } keys %{$s->{_sieve}}) {
- while ($n % $k == 0) {
- $factors->{$k}++;
- $n /= $k;
- }
-
-
- last if $k == 1;
- }
-
- return $factors;
- }
-
- sub is_prime {
- my ($s, $n) = @_;
-
- return defined $s->{_sieve}->{$n} ? 1 : 0;
- }
-
- sub divisor_count {
- my ($s, $n) = @_;
- my $factors = $s->factor($n);
-
- my ($k, $m) = (0, 1);
-
- for $k (keys %$factors) {
- $m *= $factors->{$k}+1;
- }
-
- return $m;
- }
-
- sub divisor_sum {
- my ($s, $n, $raised, @r) = @_;
- my $factors = $s->factor($n);
- my ($p, $a, $total, $sum) = (0, 0, 1, 0);
- my $k;
-
- $raised = 1 if not defined $raised;
-
- while (($p, $a) = each(%$factors)) {
- for $k (1..$a) { # sum needs to be built into every language...
- $sum += $p**($raised*$k);
- }
- $total *= 1+$sum;
- $sum = 0;
- }
-
- return $total;
- }
-
- 1;