inverse_of_factorial.pl 857 B

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. #!/usr/bin/perl
  2. # The inverse of n factorial, based on the inverse of Stirling's approximation.
  3. use 5.010;
  4. use strict;
  5. use warnings;
  6. use lib qw(../lib);
  7. use Math::AnyNum qw(:overload tau e factorial LambertW lgrt approx_cmp);
  8. use constant S => tau->sqrt->log;
  9. use constant T => tau->root(-2.0 * e);
  10. sub inverse_factorial_W {
  11. my ($n) = @_;
  12. my $L = log($n) - S;
  13. $L / LambertW($L / e) - 0.5;
  14. }
  15. sub inverse_factorial_lgrt {
  16. my ($n) = @_;
  17. lgrt(T * $n**(1 / e)) * e - 0.5;
  18. }
  19. for my $n (1 .. 100) {
  20. my $f = factorial($n);
  21. my $i = inverse_factorial_W($f);
  22. my $j = inverse_factorial_lgrt($f);
  23. printf("F(%2s!) =~ %s\n", $n, $i);
  24. if (approx_cmp($i, $j) != 0) {
  25. die "$i != $j";
  26. }
  27. if (approx_cmp($i, $n, 0) != 0) {
  28. die "However that is incorrect! (expected: $n -- got ", $i->round, ")";
  29. }
  30. }