|
| 1 | +// Copyright 2023 The XLS Authors |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +import std; |
| 16 | + |
| 17 | +// https://en.wikipedia.org/wiki/Greatest_common_divisor#Euclidean_algorithm |
| 18 | +fn gcd_euclidean<N: u32, DN: u32 = {N * u32:2}>(a: uN[N], b: uN[N]) -> uN[N] { |
| 19 | + let (gcd, _) = for (i, (a, b)) in range(u32:0, DN) { |
| 20 | + if (b == uN[N]:0) { |
| 21 | + (a, b) |
| 22 | + } else { |
| 23 | + (b, std::iterative_div_mod(a, b).1) |
| 24 | + } |
| 25 | + }((a, b)); |
| 26 | + gcd |
| 27 | +} |
| 28 | + |
| 29 | +fn gcd_binary_match<N: u32>(a: uN[N], b: uN[N], d: uN[N]) -> (uN[N], uN[N], uN[N]) { |
| 30 | + match (a[0:1], b[0:1]) { |
| 31 | + (u1:0, u1:1) => (b, a >> 1, d), |
| 32 | + (u1:1, u1:0) => (a, b >> 1, d), |
| 33 | + (u1:0, u1:0) => (a >> 1, b >> 1, d+uN[N]:1), |
| 34 | + (u1:1, u1:1) => ((a - b) >> 1, b, d), |
| 35 | + _ => fail!("unsupported_case", (uN[N]:0, uN[N]:0, uN[N]:0)), |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +// https://en.wikipedia.org/wiki/Greatest_common_divisor#Binary_GCD_algorithm |
| 40 | +fn gcd_binary<N: u32, DN: u32 = {N * u32:2}>(a: uN[N], b: uN[N]) -> uN[N] { |
| 41 | + let (a, _, d) = for (i, (a, b, d)) in range(u32:0, DN) { |
| 42 | + if (a == b) { |
| 43 | + (a, b, d) |
| 44 | + } else if (a < b) { |
| 45 | + gcd_binary_match(b, a, d) |
| 46 | + } else { |
| 47 | + gcd_binary_match(a, b, d) |
| 48 | + } |
| 49 | + }((a, b, uN[N]:0)); |
| 50 | + (a << d) |
| 51 | +} |
| 52 | + |
| 53 | +#[test] |
| 54 | +fn gcd_euclidean_test() { |
| 55 | + assert_eq(u8:6, gcd_euclidean(u8:48, u8:18)); |
| 56 | + assert_eq(u8:6, gcd_euclidean(u8:18, u8:48)); |
| 57 | +} |
| 58 | + |
| 59 | +#[test] |
| 60 | +fn gcd_binary_test() { |
| 61 | + assert_eq(u8:6, gcd_binary(u8:48, u8:18)); |
| 62 | + assert_eq(u8:6, gcd_binary(u8:18, u8:48)); |
| 63 | +} |
| 64 | + |
| 65 | +#[quickcheck(test_count=50000)] |
| 66 | +fn prop_gcd_equal(a: u32, b: u32) -> bool { |
| 67 | + gcd_euclidean<u32:32>(a, b) == gcd_binary<u32:32>(a, b) |
| 68 | +} |
0 commit comments