partitions_count.pl 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 14 August 2016
  4. # Website: https://github.com/trizen
  5. # A very fast algorithm for counting the number of partitions of a given number.
  6. # OEIS:
  7. # https://oeis.org/A000041
  8. # See also:
  9. # https://www.youtube.com/watch?v=iJ8pnCO0nTY
  10. use 5.010;
  11. use strict;
  12. use warnings;
  13. no warnings 'recursion';
  14. use Memoize qw(memoize);
  15. use Math::AnyNum qw(:overload floor ceil);
  16. memoize('partitions_count');
  17. #
  18. ## 3b^2 - b - 2n <= 0
  19. #
  20. sub b1 {
  21. my ($n) = @_;
  22. my $x = 3;
  23. my $y = -1;
  24. my $z = -2 * $n;
  25. floor((-$y + sqrt($y**2 - 4 * $x * $z)) / (2 * $x));
  26. }
  27. #
  28. ## 3b^2 + 7b - 2n+4 >= 0
  29. #
  30. sub b2 {
  31. my ($n) = @_;
  32. my $x = 3;
  33. my $y = 7;
  34. my $z = -2 * $n + 4;
  35. ceil((-$y + sqrt($y**2 - 4 * $x * $z)) / (2 * $x));
  36. }
  37. sub p {
  38. (3 * $_[0]**2 - $_[0]) / 2;
  39. }
  40. # Based on the recursive function described by Christian Schridde:
  41. # https://numberworld.blogspot.com/2013/09/sum-of-divisors-function-eulers.html
  42. sub partitions_count {
  43. my ($n) = @_;
  44. return $n if ($n <= 1);
  45. my $sum_1 = 0;
  46. foreach my $i (1 .. b1($n)) {
  47. $sum_1 += (-1)**($i - 1) * partitions_count($n - p($i));
  48. }
  49. my $sum_2 = 0;
  50. foreach my $i (1 .. b2($n)) {
  51. $sum_2 += (-1)**($i - 1) * partitions_count($n - p(-$i));
  52. }
  53. $sum_1 + $sum_2;
  54. }
  55. foreach my $n (1 .. 100) {
  56. say "p($n) = ", partitions_count($n+1);
  57. }
  58. __END__
  59. p(1) = 1
  60. p(2) = 2
  61. p(3) = 3
  62. p(4) = 5
  63. p(5) = 7
  64. p(6) = 11
  65. p(7) = 15
  66. p(8) = 22
  67. p(9) = 30
  68. p(10) = 42
  69. p(11) = 56
  70. p(12) = 77
  71. p(13) = 101
  72. p(14) = 135
  73. p(15) = 176
  74. p(16) = 231
  75. p(17) = 297
  76. p(18) = 385
  77. p(19) = 490
  78. p(20) = 627