|
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