Skip to content

Commit

Permalink
- More optimizations in Number inverse_sigma(n), by caching the div…
Browse files Browse the repository at this point in the history
…isors `d` of `n` and the prime factors of each `d-1`.

This leads to a big performance improvement.

Example:

	# This now takes ~0.3 seconds (before it took ~4 seconds)
	say inverse_sigma(9325257382230393314439814176).len   #=> 25

	# This now takes ~3.7 seconds (before it took ~6.5 seconds)
	say inverse_sigma(13!).len	#=> 53265

Also the duplicates are now removed.

	say inverse_sigma(7688)	  #=> [2800, 2928, 4575, 7687]

Previously, 2800 was inlcuded twice in the returned array.
  • Loading branch information
trizen committed Sep 10, 2019
1 parent 17682d7 commit ec6590f
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions lib/Sidef/Types/Number/Number.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10462,8 +10462,10 @@ package Sidef::Types::Number::Number {
return Sidef::Types::Array::Array->new;
}

my %seen;
my %mpz_lookup;
my %cache;
my %mpz_cache;
my %factor_cache;
my %divisor_cache;

my $P = Math::GMPz::Rmpz_init();

Expand All @@ -10473,20 +10475,28 @@ package Sidef::Types::Number::Number {
return [1] if ($n == 1);

my $key = "$n $m";
if (exists $seen{$key}) {
return $seen{$key};
if (exists $cache{$key}) {
return $cache{$key};
}

my (@R, @D);
$divisor_cache{$n} //= [Math::Prime::Util::GMP::divisors($n)];

foreach my $d (Math::Prime::Util::GMP::divisors($n)) {
foreach my $d (@{$divisor_cache{$n}}) {
if ($d >= $m) {

if ($d < ULONG_MAX) {
push @D, $d;
}
else {
push @D, ($mpz_lookup{$d} //= Math::GMPz::Rmpz_init_set_str("$d", 10));
push @D, ($mpz_cache{$d} //= Math::GMPz::Rmpz_init_set_str("$d", 10));
}

$factor_cache{$D[-1]} //= do {
my %factors;
@factors{Math::Prime::Util::GMP::factor($D[-1] - 1)} = ();
[keys %factors];
};
}
}

Expand All @@ -10495,11 +10505,7 @@ package Sidef::Types::Number::Number {
}

foreach my $d (@D) {

my %factors;
@factors{Math::Prime::Util::GMP::factor($d - 1)} = ();

foreach my $p (keys %factors) {
foreach my $p (@{$factor_cache{$d}}) {

if (!ref($d) and $p < ULONG_MAX) { # optimization for small d and p

Expand Down Expand Up @@ -10642,10 +10648,13 @@ package Sidef::Types::Number::Number {
}
}

$seen{$key} = \@R;
$cache{$key} = \@R;
}
->($n, 3);

my %seen;

@$results = grep { !$seen{$_}++ } @$results;
@$results = sort { $a <=> $b } @$results;
@$results = map { ref($_) ? bless(\$_) : __PACKAGE__->_set_uint($_) } @$results;

Expand Down

0 comments on commit ec6590f

Please sign in to comment.