batch_gcd_algorithm.sf 1003 B

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. #!/usr/bin/ruby
  2. # Batch greatest common divisor algorithm.
  3. # Algorithm from:
  4. # https://web.archive.org/web/20220116042107/http://cr.yp.to/talks/2012.12.28/slides.pdf
  5. func batch_gcd(X) {
  6. var prods = gather {
  7. take(X)
  8. while (X.len > 1) {
  9. X = range((X.len+1)>>1).map{|i| X.slice(i<<1, 2).prod }
  10. take(X)
  11. }
  12. }
  13. var R = prods.pop
  14. while (prods) {
  15. X = prods.pop
  16. R = X.map_kv {|k,v| R[k>>1] % v.sqr }
  17. }
  18. R ~Z X -> map_2d {|r,n| gcd(r/n, n) }
  19. }
  20. func batch_gcd_naive(X) { # a simpler approach (much slower)
  21. X.map_reduce {|a,b| a*b } ~Z X -> map_2d {|r,n| gcd(r/n, n) }
  22. }
  23. var arr = [43*97, 41*29, 43*503, 503*863]
  24. say var a = batch_gcd(arr) #=> [43, 1, 21629, 503]
  25. say var b = batch_gcd_naive(arr) #=> [1, 1, 43, 503]
  26. assert_eq(a, %n[43, 1, 21629, 503])
  27. assert_eq(b, %n[1, 1, 43, 503])
  28. assert(batch_gcd(1000.of { irand(2**1024) }).len, 1000)
  29. assert(batch_gcd(1001.of { irand(2**1024) }).len, 1001)