harmonic_numbers_from_powers_mpz.pl 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 29 July 2017
  5. # https://github.com/trizen
  6. # Computation of the nth-harmonic number, using perfect powers.
  7. use 5.010;
  8. use strict;
  9. use warnings;
  10. use Math::GMPz;
  11. sub harmonic_numbers_from_powers {
  12. my ($n) = @_;
  13. my @seen;
  14. my $num = Math::GMPz::Rmpz_init_set_ui($n <= 0 ? 0 : 1);
  15. my $den = Math::GMPz::Rmpz_init_set_ui(1);
  16. foreach my $k (2 .. $n) {
  17. if (not exists $seen[$k]) {
  18. my $p = $k;
  19. do {
  20. $seen[$p] = undef;
  21. } while (($p *= $k) <= $n);
  22. my $g = $p / $k;
  23. my $t = ($g - 1) / ($k - 1);
  24. Math::GMPz::Rmpz_mul_ui($num, $num, $g);
  25. $t == 1
  26. ? Math::GMPz::Rmpz_add($num, $num, $den)
  27. : Math::GMPz::Rmpz_addmul_ui($num, $den, $t);
  28. Math::GMPz::Rmpz_mul_ui($den, $den, $g);
  29. }
  30. }
  31. my $gcd = Math::GMPz::Rmpz_init();
  32. Math::GMPz::Rmpz_gcd($gcd, $num, $den);
  33. Math::GMPz::Rmpz_divexact($num, $num, $gcd);
  34. Math::GMPz::Rmpz_divexact($den, $den, $gcd);
  35. return ($num, $den);
  36. }
  37. foreach my $n (0 .. 30) {
  38. printf "%20s / %-20s\n", harmonic_numbers_from_powers($n);
  39. }