Skip to content

Commit d2da104

Browse files
Merge pull request #935 from proppy:gcd
PiperOrigin-RevId: 638888730
2 parents fd7c161 + c7b7a94 commit d2da104

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

xls/examples/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,3 +1011,15 @@ xls_dslx_verilog(
10111011
library = "passthrough_dslx",
10121012
verilog_file = "passthrough.sv",
10131013
)
1014+
1015+
xls_dslx_library(
1016+
name = "gcd_dslx",
1017+
srcs = ["gcd.x"],
1018+
)
1019+
1020+
xls_dslx_test(
1021+
name = "gcd_test",
1022+
size = "small",
1023+
srcs = ["gcd.x"],
1024+
deps = [":gcd_dslx"],
1025+
)

xls/examples/gcd.x

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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

Comments
 (0)