700 Eulercoin -- v2.pl 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 10 February 2020
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=700
  6. # Runtime: 0.059s
  7. # Using the denominators of Farey approximations of 1504170715041707 / 4503599627370517.
  8. # See also:
  9. # https://en.wikipedia.org/wiki/Farey_sequence
  10. use 5.020;
  11. use warnings;
  12. use ntheory qw(:all);
  13. use experimental qw(signatures);
  14. sub farey_approximations($nu, $de, $callback) {
  15. my $a1 = divint($nu, $de);
  16. my $b1 = 1;
  17. my $a2 = $a1+1;
  18. my $b2 = 1;
  19. for (;;) {
  20. my $a3 = $a1+$a2;
  21. my $b3 = $b1+$b2;
  22. if (mulint($de, $a3) < mulint($nu, $b3)) {
  23. ($a1, $b1) = ($a3, $b3);
  24. }
  25. else {
  26. ($a2, $b2) = ($a3, $b3);
  27. }
  28. $callback->($a3, $b3) || last;
  29. }
  30. }
  31. my $a = 1504170715041707;
  32. my $b = 4503599627370517;
  33. my $min = $a;
  34. my $sum = $min;
  35. farey_approximations($a, $b, sub ($n, $d) {
  36. my $t = mulmod($a, $d, $b);
  37. if ($t < $min) {
  38. $sum += $t;
  39. $min = $t;
  40. return $t > 1;
  41. }
  42. return 1;
  43. });
  44. say $sum;