bernoulli_numbers_from_factorials_mpq.pl 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 02 December 2017
  4. # https://github.com/trizen
  5. # A new algorithm for computing Bernoulli numbers.
  6. # Inspired from Norman J. Wildberger video lecture:
  7. # https://www.youtube.com/watch?v=qmMs6tf8qZ8
  8. # See also:
  9. # https://en.wikipedia.org/wiki/Bernoulli_number#Connection_with_Pascal’s_triangle
  10. use 5.010;
  11. use strict;
  12. use warnings;
  13. use Math::GMPq;
  14. use Math::GMPz;
  15. sub bernoulli_numbers {
  16. my ($n) = @_;
  17. my @B;
  18. my @factorial;
  19. Math::GMPq::Rmpq_set_ui($B[0] = Math::GMPq::Rmpq_init(), 1, 1);
  20. Math::GMPq::Rmpq_set_ui($B[$_] = Math::GMPq::Rmpq_init(), 0, 1) for (1 .. $n);
  21. my $t = Math::GMPq::Rmpq_init();
  22. foreach my $i (1 .. $n) {
  23. if ($i % 2 != 0 and $i > 1) {
  24. next;
  25. }
  26. foreach my $k (0 .. $i - 1) {
  27. if ($k % 2 != 0 and $k > 1) {
  28. next;
  29. }
  30. my $r = $i - $k + 1;
  31. $factorial[$r] //= do {
  32. my $t = Math::GMPz::Rmpz_init();
  33. Math::GMPz::Rmpz_fac_ui($t, $r);
  34. $t;
  35. };
  36. Math::GMPq::Rmpq_div_z($t, $B[$k], $factorial[$r]);
  37. Math::GMPq::Rmpq_sub($B[$i], $B[$i], $t);
  38. }
  39. }
  40. for (my $k = 2; $k <= $#B; $k += 2) {
  41. Math::GMPq::Rmpq_mul_z($B[$k], $B[$k], $factorial[$k]);
  42. }
  43. return @B;
  44. }
  45. my @B = bernoulli_numbers(100); # first 100 Bernoulli numbers
  46. foreach my $i (0 .. $#B) {
  47. say "B($i) = $B[$i]";
  48. }