|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift Numerics open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2021 Apple Inc. and the Swift Numerics project authors |
| 5 | +// Copyright (c) 2021-2024 Apple Inc. and the Swift Numerics project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
9 | 9 | //
|
10 | 10 | //===----------------------------------------------------------------------===//
|
11 | 11 |
|
12 |
| -/// The greatest common divisor of `a` and `b`. |
| 12 | +/// The [greatest common divisor][gcd] of `a` and `b`. |
13 | 13 | ///
|
14 | 14 | /// If both inputs are zero, the result is zero. If one input is zero, the
|
15 | 15 | /// result is the absolute value of the other input.
|
|
21 | 21 | /// gcd(Int.min, Int.min) // Overflow error
|
22 | 22 | /// gcd(Int.min, 0) // Overflow error
|
23 | 23 | ///
|
24 |
| -/// [wiki]: https://en.wikipedia.org/wiki/Greatest_common_divisor |
| 24 | +/// [gcd]: https://en.wikipedia.org/wiki/Greatest_common_divisor |
25 | 25 | @inlinable
|
26 | 26 | public func gcd<T: BinaryInteger>(_ a: T, _ b: T) -> T {
|
27 |
| - var x = a.magnitude |
28 |
| - var y = b.magnitude |
29 |
| - |
30 |
| - if x == 0 { return T(y) } |
31 |
| - if y == 0 { return T(x) } |
32 |
| - |
33 |
| - let xtz = x.trailingZeroBitCount |
34 |
| - let ytz = y.trailingZeroBitCount |
35 |
| - |
36 |
| - y >>= ytz |
37 |
| - |
38 |
| - // The binary GCD algorithm |
39 |
| - // |
40 |
| - // After the right-shift in the loop, both x and y are odd. Each pass removes |
41 |
| - // at least one low-order bit from the larger of the two, so the number of |
42 |
| - // iterations is bounded by the sum of the bit-widths of the inputs. |
43 |
| - // |
44 |
| - // A tighter bound is the maximum bit-width of the inputs, which is achieved |
45 |
| - // by odd numbers that sum to a power of 2, though the proof is more involved. |
46 |
| - repeat { |
47 |
| - x >>= x.trailingZeroBitCount |
48 |
| - if x < y { swap(&x, &y) } |
49 |
| - x -= y |
50 |
| - } while x != 0 |
51 |
| - |
52 |
| - return T(y << min(xtz, ytz)) |
| 27 | + var x = a |
| 28 | + var y = b |
| 29 | + if x.magnitude < y.magnitude { swap(&x, &y) } |
| 30 | + // Avoid overflow when x = signed min, y = -1. |
| 31 | + if y.magnitude == 1 { return 1 } |
| 32 | + // Euclidean algorithm for GCD. It's worth using Lehmer instead for larger |
| 33 | + // integer types, but for now this is good and dead-simple and faster than |
| 34 | + // the other obvious choice, the binary algorithm. |
| 35 | + while y != 0 { (x, y) = (y, x%y) } |
| 36 | + // Try to convert result to T. |
| 37 | + if let result = T(exactly: x.magnitude) { return result } |
| 38 | + // If that fails, produce a diagnostic. |
| 39 | + fatalError("GCD (\(x)) is not representable as \(T.self).") |
53 | 40 | }
|
0 commit comments