divisors_of_factorial_in_range_iterator.pl 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 18 December 2018
  4. # https://github.com/trizen
  5. # Generate the divisors of n! in a given range, using a closure iterator.
  6. # See also:
  7. # https://en.wikipedia.org/wiki/Smooth_number
  8. use 5.020;
  9. use warnings;
  10. use experimental qw(signatures);
  11. use ntheory qw(vecmin primes todigits vecsum valuation factorial);
  12. sub divisors_of_factorial_iterator ($f, $low, $high) {
  13. my @primes = map { [$_, ($f - vecsum(todigits($f, $_))) / ($_ - 1)] } @{primes($f)};
  14. my @s = map { [1] } 1 .. @primes;
  15. sub {
  16. my $n = 0;
  17. while ($n < $low) {
  18. $n = vecmin(map { $_->[0] } @s);
  19. foreach my $i (0 .. $#primes) {
  20. shift(@{$s[$i]}) if ($s[$i][0] == $n);
  21. my $p = $primes[$i][0];
  22. last if valuation($n, $p) >= $primes[$i][1];
  23. push(@{$s[$i]}, $n * $p);
  24. }
  25. }
  26. return undef if ($n > $high);
  27. return $n;
  28. }
  29. }
  30. my $n = 30;
  31. my $low = 10**8;
  32. my $high = 10**12;
  33. my $iter = divisors_of_factorial_iterator($n, $low, $high);
  34. my $sum = 0;
  35. for (my $n = $iter->() ; defined($n) ; $n = $iter->()) {
  36. $sum += $n;
  37. }
  38. say "Sum of divisors of $n! between $low and $high = $sum";
  39. __END__
  40. Sum of divisors of 30! between 100000000 and 1000000000000 = 53791918385367774