arithmetic_geometric_mean_complex.pl 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 17 April 2017
  5. # https://github.com/trizen
  6. # Implementation of the arithmetic-geometric mean function, in complex numbers.
  7. # See also:
  8. # https://en.wikipedia.org/wiki/Arithmetic%E2%80%93geometric_mean
  9. # https://www.mathworks.com/help/symbolic/mupad_ref/numeric-gaussagm.html
  10. use 5.010;
  11. use strict;
  12. use warnings;
  13. use Math::MPC;
  14. our $PREC = 192;
  15. our $ROUND = Math::MPC::MPC_RNDNN;
  16. # agm(a, -a) = 0
  17. # agm(0, x) = 0
  18. # agm(x, 0) = 0
  19. sub agm($$) {
  20. my ($x, $y) = @_;
  21. my $a0 = Math::MPC::Rmpc_init2($PREC);
  22. my $g0 = Math::MPC::Rmpc_init2($PREC);
  23. Math::MPC::Rmpc_set_str($a0, $x, 10, $ROUND);
  24. Math::MPC::Rmpc_set_str($g0, $y, 10, $ROUND);
  25. my $a1 = Math::MPC::Rmpc_init2($PREC);
  26. my $g1 = Math::MPC::Rmpc_init2($PREC);
  27. my $t = Math::MPC::Rmpc_init2($PREC);
  28. # agm(0, x) = 0
  29. if (!Math::MPC::Rmpc_cmp_si_si($a0, 0, 0)) {
  30. return $a0;
  31. }
  32. # agm(x, 0) = 0
  33. if (!Math::MPC::Rmpc_cmp_si_si($g0, 0, 0)) {
  34. return $g0;
  35. }
  36. my $count = 0;
  37. {
  38. Math::MPC::Rmpc_add($a1, $a0, $g0, $ROUND);
  39. Math::MPC::Rmpc_div_2exp($a1, $a1, 1, $ROUND);
  40. Math::MPC::Rmpc_mul($g1, $a0, $g0, $ROUND);
  41. Math::MPC::Rmpc_add($t, $a0, $g0, $ROUND);
  42. Math::MPC::Rmpc_sqr($t, $t, $ROUND);
  43. Math::MPC::Rmpc_cmp_si_si($t, 0, 0) || return $t;
  44. Math::MPC::Rmpc_div($g1, $g1, $t, $ROUND);
  45. Math::MPC::Rmpc_sqrt($g1, $g1, $ROUND);
  46. Math::MPC::Rmpc_add($t, $a0, $g0, $ROUND);
  47. Math::MPC::Rmpc_mul($g1, $g1, $t, $ROUND);
  48. if (Math::MPC::Rmpc_cmp($a0, $a1) and ++$count < $PREC) {
  49. Math::MPC::Rmpc_set($a0, $a1, $ROUND);
  50. Math::MPC::Rmpc_set($g0, $g1, $ROUND);
  51. redo;
  52. }
  53. }
  54. return $g0;
  55. }
  56. say agm(3, 4);
  57. say agm(-1, 2);
  58. say agm(1, -2);
  59. say agm(0, 5);
  60. say agm(-10, 3.14159265358979323846264338327950288419716939938);
  61. say agm(10, 0);
  62. say agm(10, -10);
  63. say agm(10, 10);
  64. say agm(-3, -4);
  65. say agm(-1, -1);
  66. say agm(-1, -2);
  67. say agm(-2, -2);
  68. say agm(2, -3);