num ← num ##.gcd num ⍝ Greatest Common Divisor. ⍝ Euclid ¯330-¯275. An illustration of tail recursion. gcd←{ ⍝ Greatest common divisor. ⍵=0:|⍺ ⍵ ∇ ⍵|⍺ } NB: This function is for illustrative purposes only; GCD and LCM are primitive functions ∨ and ∧. Wikipedia says: "The original algorithm as described by Euclid treated it as a geometric problem, and hence used repeated subtraction of the smaller number from the larger number rather than integer division ... which is considerably less efficient than ... (using residue)." Ref: http://en.wikipedia.org/wiki/Euclidean_algorithm Euclid might have coded the following, which works for positive arguments: gcd←{ ⍝ Euclid's algorithm. ⍺<⍵: ⍺ ∇ ⍵-⍺ ⍝ ... using repeated ⍺>⍵: ⍵ ∇ ⍺-⍵ ⍝ ... subtraction. ⍺=⍵: ⍺ } Binary GCD ---------- This algorithm, which takes a pair of non-negative whole (unsigned integer) numbers as argument, is suitable for implementing GCD in a low-level compiled or assembly language. In such languages, 2|⍵ and ⍺÷2 are fast operations. bgcd←{ ⍝ Binary gcd. 0∊⍵:+/⍵ ⍝ either is 0: m ? m : n 0 0≡2|⍵:2×∇ ⍵÷2 ⍝ even even: (∇ (m >> 1) (n >> 1)) << 1 0 1≡2|⍵:∇ ⍵÷2 1 ⍝ even odd: ∇ (m >> 1) n 1 0≡2|⍵:∇ ⍵÷1 2 ⍝ odd even: ∇ m (n >> 1) ≤/⍵:∇(-\⍵)÷1 ¯2 ⍝ odd odd: m≤n: ∇ m (n-m >> 1) ∇(⌽-\⌽⍵)÷¯2 1 ⍝ odd odd: m>n: ∇ (m-n >> 1) n } bgcd 105 330 ⍝ takes a pair of non-negative whole numbers. 15 Ref: http://en.wikipedia.org/wiki/Binary_gcd Array GCD --------- We can modify the coding slightly to find the GCDs of conformable (possibly nested) arrays in parallel: gcds←{ ⍝ Array-GCD. ⍺≡⍺+⍺:|⍵ ⍝ all 0s: done. (⍺⌊⍵)∇(⍺⌊⍵)|⍺⌈⍵ ⍝ min ∇ min | max. } ⎕←pvec←sieve 2 to 80 ⍝ primes 2..80 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 ⎕←tvec←×/¨3,/pvec ⍝ products of consecutive triples. 30 105 385 1001 2431 4199 7429 12673 20677 33263 47027 65231 82861 107113 146969 190747 241133 290177 347261 409457 ⎕←ll rr←4 5∘⍴¨0 ¯1⌽¨⊂tvec ⍝ matrices of adjacent triple products. 30 105 385 1001 2431 409457 30 105 385 1001 4199 7429 12673 20677 33263 2431 4199 7429 12673 20677 47027 65231 82861 107113 146969 33263 47027 65231 82861 107113 190747 241133 290177 347261 409457 146969 190747 241133 290177 347261 ll gcd¨rr ⍝ GCDs using each. 1 15 35 77 143 221 323 437 667 899 1147 1517 1763 2021 2491 3127 3599 4087 4757 5183 ll gcds rr ⍝ parallel GCDs. 1 15 35 77 143 221 323 437 667 899 1147 1517 1763 2021 2491 3127 3599 4087 4757 5183 cmpx'll gcd¨rr' 'll gcds rr' ⍝ timing comparison: parallel is faster. ll gcd¨rr 1.2E¯4 0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ ll gcds rr 5.2E¯5 -56% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ (↓ll) gcds ↓rr ⍝ nested GCDs. ┌──────────────┬───────────────────┬────────────────────────┬────────────────────────┐ │1 15 35 77 143│221 323 437 667 899│1147 1517 1763 2021 2491│3127 3599 4087 4757 5183│ └──────────────┴───────────────────┴────────────────────────┴────────────────────────┘ A better version for non-integral arguments ------------------------------------------- Euclid's algorithm works well for whole-number arguments but gives poor results for floating-point numbers. We can generalise Euclid to →rational← arguments by noting that: (A÷B) gcd (C÷D) ←→ (A gcd C) ÷ (B lcm D) where lcm is least-common-multiple. The following code does the trick: ggcd←{ ⍝ General gcd. (a b)(c d)←rational¨⍺ ⍵ ⍝ rational approximations. lcm←{⍺×⍵÷⍺ gcd ⍵} ⍝ least common multiple. (a gcd c)÷b lcm d ⍝ (see notes.rats). } then: (1 to 11) ggcd¨ 0.111 ⍝ Gianluigi Quario's example. 0.001 0.001 0.003 0.001 0.001 0.003 0.001 0.001 0.003 0.001 0.001 Examples: 105 gcd 330 15 factors (3×5×7) gcd 5×7×11 5 7 lcm←{⍺×⍵÷⍺ gcd ⍵} ⍝ least common multiple factors (3×5×7) lcm 5×7×11 3 5 7 11 24 (,÷gcd) 36 ⍝ simplify: 24/36 → 2/3. 2 3 See also: sieve factors nats rats rational Back to: contents Back to: Workspaces