Math-Prime-Util

 view release on metacpan or  search on metacpan

lib/Math/Prime/Util/PP.pm  view on Meta::CPAN

    }

    print "   ... inverse_totient phase 1 complete ...\n" if $_verbose;

    # 2. Process the divisors in reverse order.
    for my $dinfo (reverse @DIVINFO) {
      my($d,@L) = @$dinfo;
      my %todelete;
      my @T;
      # Multiply through by $pp
      for my $dset (@L) {
        if (defined $r{$dset->[0]}) {
          my($d2,$pp,$F) = @$dset;
          push @T, [$F, [map { Mmulint($pp,$_) } @{$r{$d2}}]];
          $todelete{$d2} = 1 if $needed{$d2} >= $d;
        }
      }
      # Delete intermediate data that isn't needed any more
      delete $r{$_} for keys %todelete;
      # Append the multiplied lists.
      push @{$r{$_->[0]}}, @{$_->[1]} for @T;
    }
    undef %needed;
    print "   ... inverse_totient phase 2 complete ...\n" if $_verbose;

    return (defined $r{$n}) ? @{Mvecsorti($r{$n})} : ();
  }
}

sub _euler_phi_range {
  my($lo, $hi) = @_;
  validate_integer($lo);
  validate_integer($hi);

  my @totients;
  while ($lo < 0 && $lo <= $hi) {
    push @totients, 0;
    $lo++;
  }
  return @totients if $hi < $lo;

  if ($hi > 2**30 || $hi-$lo < 100) {
    ($lo,$hi) = (tobigint($lo),tobigint($hi)) if $hi > 2**49;
    push @totients, euler_phi($lo++)  while $lo <= $hi;
  } else {
    my @tot = (0 .. $hi);
    foreach my $i (2 .. $hi) {
      next unless $tot[$i] == $i;
      $tot[$i] = $i-1;
      foreach my $j (2 .. int($hi / $i)) {
        $tot[$i*$j] -= $tot[$i*$j]/$i;
      }
    }
    splice(@tot, 0, $lo) if $lo > 0;
    push @totients, @tot;
  }
  @totients;
}

sub _sumtot {
  my($n, $cdata, $ecache) = @_;
  return $cdata->[$n] if $n <= 0+$#$cdata;
  return $ecache->{$n} if defined $ecache->{$n};

  my $sum = Mmulint($n, $n+1) >> 1;
  my $s = sqrtint($n);
  my $lim = Mdivint($n, $s+1);

  my($x, $nextx) = ($n, Mdivint($n,2));
  $sum -= Mmulint($x - $nextx, $cdata->[1]);
  for my $k (2 .. $lim) {
    ($x,$nextx) = ($nextx, Mdivint($n,$k+1));
    $sum -= ($x <= 0+$#$cdata) ? $cdata->[$x] : _sumtot($x, $cdata, $ecache);
    $sum -= Mmulint($x - $nextx,
                    ($k <= $#$cdata) ? $cdata->[$k] : _sumtot($k, $cdata, $ecache));
  }
  if ($s > $lim) {
    ($x,$nextx) = ($nextx, Mdivint($n,$s+1));
    $sum -= Mmulint($x - $nextx,
                    ($s <= 0+$#$cdata) ? $cdata->[$s] : _sumtot($s, $cdata, $ecache));
  }
  $ecache->{$n} = $sum;
  $sum;
}

sub sumtotient {
  my($n) = @_;
  validate_integer_nonneg($n);
  return $n if $n <= 2;

  if ($n < 900) {     # Simple linear sum for small values.
    my $sum = 0;
    $sum += $_ for Mtotient(1,$n);
    return $sum;
  }

  my $cbrt = Mrootint($n,3);
  my $csize = Mvecprod(4, $cbrt, $cbrt);
  $csize = 50_000_000 if $csize > 50_000_000;  # Limit memory use to ~2.5GB
  my @sumcache = Mtotient(0,$csize);
  $sumcache[$_] += $sumcache[$_-1] for 2 .. $csize;
  _sumtot($n, \@sumcache, {});
}


sub prime_bigomega {
  my($n) = @_;
  validate_integer_abs($n);
  return scalar(Mfactor($n));
}
sub prime_omega {
  my($n) = @_;
  validate_integer_abs($n);
  return scalar(Mfactor_exp($n));
}

sub moebius {
  return _moebius_range(@_) if scalar @_ > 1;
  my($n) = @_;
  validate_integer_abs($n);
  return ($n == 1) ? 1 : 0  if $n <= 1;
  return 0 if ($n >= 49) && (!($n % 4) || !($n % 9) || !($n % 25) || !($n%49) );
  my @factors = Mfactor($n);
  foreach my $i (1 .. $#factors) {
    return 0 if $factors[$i] == $factors[$i-1];
  }
  return ((scalar @factors) % 2) ? -1 : 1;
}
sub is_square_free {
  return (Mmoebius($_[0]) != 0) ? 1 : 0;
}

sub is_odd {
  my($n) = @_;
  validate_integer($n);
  # Note:  If n is a Math::BigInt (Calc), then performance:
  #    0.25x  $n->is_odd()                           # method is fastest
  #    0.34x  (substr($n,-1,1) =~ tr/13579/13579/)   # Perl look at string
  #    0.46x  is_odd($n)                             # XS looks at the string
  #    1.0x   $n % 2 ? 1 : 0



( run in 1.096 second using v1.01-cache-2.11-cpan-39bf76dae61 )