bernoulli_numbers_seidel.pl 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 06 October 2016
  5. # Website: https://github.com/trizen
  6. # Algorithm from:
  7. # https://oeis.org/wiki/User:Peter_Luschny/ComputationAndAsymptoticsOfBernoulliNumbers#Seidel
  8. use 5.010;
  9. use strict;
  10. use warnings;
  11. use Math::AnyNum;
  12. sub bernoulli_seidel {
  13. my ($n) = @_;
  14. $n == 0 and return Math::AnyNum->one;
  15. $n == 1 and return Math::AnyNum->new('1/2');
  16. $n % 2 and return Math::AnyNum->zero;
  17. state $one = Math::GMPz::Rmpz_init_set_ui(1);
  18. my @D = (
  19. Math::GMPz::Rmpz_init_set_ui(0),
  20. Math::GMPz::Rmpz_init_set_ui(1),
  21. map { Math::GMPz::Rmpz_init_set_ui(0) } (1 .. $n / 2 - 1)
  22. );
  23. my ($h, $w) = (1, 1);
  24. foreach my $i (0 .. $n - 1) {
  25. if ($w ^= 1) {
  26. Math::GMPz::Rmpz_add($D[$_], $D[$_], $D[$_ - 1]) for (1 .. $h - 1);
  27. }
  28. else {
  29. $w = $h++;
  30. Math::GMPz::Rmpz_add($D[$w], $D[$w], $D[$w + 1]) while --$w;
  31. }
  32. }
  33. Math::AnyNum->new($D[$h - 1]) / Math::AnyNum->new((($one << ($n + 1)) - 2) * ($n % 4 == 0 ? -1 : 1));
  34. }
  35. foreach my $i (0 .. 50) {
  36. printf "B%-3d = %s\n", 2 * $i, bernoulli_seidel(2 * $i);
  37. }