192 Best Approximations.pl 994 B

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. #!/usr/bin/perl
  2. # Using Farey approximations (Mediants and binary search).
  3. # See also:
  4. # https://en.wikipedia.org/wiki/Stern%E2%80%93Brocot_tree
  5. # Runtime: ~2 minutes.
  6. # https://projecteuler.net/problem=192
  7. use 5.020;
  8. use warnings;
  9. use Math::GMPz;
  10. use experimental qw(signatures);
  11. use ntheory qw(is_square sqrtint);
  12. sub best_approximation($n, $lim) {
  13. my $x = Math::GMPz->new(sqrtint($n));
  14. my $a1 = $x;
  15. my $b1 = Math::GMPz->new(1);
  16. my $a2 = $x + 1;
  17. my $b2 = Math::GMPz->new(1);
  18. while ($b1 + $b2 <= $lim) {
  19. my $a3 = $a1 + $a2;
  20. my $b3 = $b1 + $b2;
  21. if ($a3 * $a3 < $n * $b3 * $b3) {
  22. ($a1, $b1) = ($a3, $b3);
  23. }
  24. else {
  25. ($a2, $b2) = ($a3, $b3);
  26. }
  27. }
  28. if (($a1 * $b2 + $a2 * $b1)**2 > $n * (2 * $b1 * $b2)**2) {
  29. return $b1;
  30. }
  31. return $b2;
  32. }
  33. my $sum = 0;
  34. foreach my $n (1 .. 100_000) {
  35. next if is_square($n);
  36. $sum += best_approximation($n, 1e12);
  37. }
  38. say $sum;