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