exact.pl 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 25 July 2017
  4. # https://github.com/trizen
  5. # An efficient algorithm for computing sigma_k(n!), where k > 0.
  6. use 5.020;
  7. use strict;
  8. use warnings;
  9. use experimental qw(signatures);
  10. use ntheory qw(forprimes vecsum todigits :all);
  11. use Math::AnyNum qw(ipow factorial);
  12. prime_precalc(3e7);
  13. my $t = Math::GMPz::Rmpz_init();
  14. sub sigma_of_factorial ($n) {
  15. my $sigma = Math::GMPz::Rmpz_init_set_ui(1);
  16. forprimes {
  17. my $p = $_;
  18. my $k = ($n - vecsum(todigits($n, $p))) / ($p - 1);
  19. if (log($p) * ($k + 1) > log(2) * 63) {
  20. #$sigma *= ((ipow($p, ($k + 1)) - 1) / ($p - 1));
  21. Math::GMPz::Rmpz_ui_pow_ui($t, $p, $k + 1);
  22. Math::GMPz::Rmpz_sub_ui($t, $t, 1);
  23. Math::GMPz::Rmpz_divexact_ui($t, $t, $p - 1);
  24. Math::GMPz::Rmpz_mul($sigma, $sigma, $t);
  25. }
  26. else {
  27. #$sigma *= divint(powint($p, $k+1) - 1, $p-1);
  28. Math::GMPz::Rmpz_mul_ui($sigma, $sigma, divint(powint($p, $k + 1) - 1, $p - 1));
  29. }
  30. } $n;
  31. return $sigma;
  32. }
  33. #say sigma_of_factorial(10, 1); # sigma_1(10!) = 15334088
  34. #say sigma_of_factorial(10, 2); # sigma_2(10!) = 20993420690550
  35. #say sigma_of_factorial( 8, 3); # sigma_3( 8!) = 78640578066960
  36. # Least k > 0 such that sigma(k!) >= n*k!.
  37. #my @array = (1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, 7879, 13859, 24247, 42683, 75037, 131707, 230773);
  38. my @array = (1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, 7879, 13859, 24247, 42683, 75037, 131707, 230773, 405401, 710569, 1246379, 2185021, 3831913, 6720059, 11781551, 20657677);
  39. say "Sanity checking...";
  40. foreach my $n (0 .. $#array) {
  41. my $k = $array[$n];
  42. say "Testing: $k";
  43. my $s = Math::AnyNum->new(sigma_of_factorial($k));
  44. my $t = $n * factorial($k);
  45. $s >= $t or die "error for $k";
  46. next if $k == 1;
  47. my $s2 = Math::AnyNum->new(sigma_of_factorial($k - 1));
  48. my $t2 = $n * factorial($k - 1);
  49. $s2 >= $t2 and die "too large: $k";
  50. }
  51. say "Test passed...";
  52. #say sigma_of_factorial(75037,1);
  53. # 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, 7879, 13859, 24247, 42683, 75037
  54. my $n = 0;
  55. local $| = '1';
  56. my $k = 1;
  57. my $factorial = factorial($k);
  58. $factorial = Math::GMPz->new("$factorial");
  59. for (; $k <= 1e6 ; ++$k) {
  60. while (sigma_of_factorial($k) >= $n * $factorial) {
  61. print($k, ", ");
  62. ++$n;
  63. }
  64. $factorial *= ($k + 1);
  65. }
  66. __END__
  67. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, perl r.pl 2.13s user 0.01s system 99% cpu 2.140 total
  68. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, perl r.pl 0.77s user 0.02s system 99% cpu 0.794 total
  69. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, perl r.pl 0.77s user 0.02s system 99% cpu 0.788 total
  70. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, perl r.pl 0.40s user 0.02s system 99% cpu 0.423 total
  71. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, perl r.pl 0.19s user 0.01s system 99% cpu 0.203 total
  72. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, perl r.pl 2.94s user 0.01s system 99% cpu 2.967 total
  73. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, perl r.pl 2.95s user 0.02s system 99% cpu 2.974 total
  74. 1, 1, 3, 5, 9, 14, 23, 43, 79, 149, 263, 461, 823, 1451, 2549, 4483, perl r.pl 2.93s user 0.02s system 98% cpu 3.003 total