logarithmic_root_mpfr.pl 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 17 September 2016
  5. # Website: https://github.com/trizen
  6. # Logarithmic root of n.
  7. # Solves c = x^x, where "c" is known.
  8. # (based on Newton's method for nth-root)
  9. # Example: 100 = x^x
  10. # x = lgrt(100)
  11. # x =~ 3.59728502354042
  12. # The function is defined in real numbers for any value >= 0.7
  13. use 5.010;
  14. use strict;
  15. use warnings;
  16. use Math::MPFR;
  17. my $PREC = 128; # can be tweaked
  18. my $ROUND = Math::MPFR::MPFR_RNDN();
  19. sub lgrt {
  20. my ($c) = @_;
  21. if (ref($c) ne 'Math::MPFR') {
  22. my $n = Math::MPFR::Rmpfr_init2($PREC);
  23. Math::MPFR::Rmpfr_set_str($n, "$c", 10, $ROUND);
  24. $c = $n;
  25. }
  26. my $p = Math::MPFR::Rmpfr_init2($PREC);
  27. Math::MPFR::Rmpfr_ui_pow_ui($p, 10, $PREC >> 2, $ROUND);
  28. Math::MPFR::Rmpfr_ui_div($p, 1, $p, $ROUND);
  29. my $d = Math::MPFR::Rmpfr_init2($PREC);
  30. Math::MPFR::Rmpfr_log($d, $c, $ROUND);
  31. my $x = Math::MPFR::Rmpfr_init2($PREC);
  32. Math::MPFR::Rmpfr_set_ui($x, 1, $ROUND);
  33. my $y = Math::MPFR::Rmpfr_init2($PREC);
  34. Math::MPFR::Rmpfr_set_ui($y, 0, $ROUND);
  35. my $tmp = Math::MPFR::Rmpfr_init2($PREC);
  36. while (1) {
  37. Math::MPFR::Rmpfr_sub($tmp, $x, $y, $ROUND);
  38. Math::MPFR::Rmpfr_cmpabs($tmp, $p) <= 0 and last;
  39. Math::MPFR::Rmpfr_set($y, $x, $ROUND);
  40. Math::MPFR::Rmpfr_log($tmp, $x, $ROUND);
  41. Math::MPFR::Rmpfr_add_ui($tmp, $tmp, 1, $ROUND);
  42. Math::MPFR::Rmpfr_add($x, $x, $d, $ROUND);
  43. Math::MPFR::Rmpfr_div($x, $x, $tmp, $ROUND);
  44. }
  45. $x;
  46. }
  47. say lgrt(100); # 3.597285023540417505497652251782286069146