1use std::cmp::min;
2use std::convert::{TryFrom, TryInto};
3use std::fmt::Debug;
4use std::mem::swap;
5use std::ops::{ShlAssign, ShrAssign, SubAssign};
6pub fn gcd<T>(mut num1: T, mut num2: T) -> T
21where
22 T: Copy
23 + PartialEq
24 + PartialOrd
25 + ShrAssign
26 + ShlAssign
27 + SubAssign
28 + TryFrom<usize>
29 + TryInto<usize>,
30 <T as TryFrom<usize>>::Error: Debug,
31 <T as TryInto<usize>>::Error: Debug,
32{
33 if num1.try_into().unwrap() == 0 {
34 return num2;
35 } else if num2.try_into().unwrap() == 0 {
36 return num1;
37 }
38
39 let min_twos = {
40 let twos_num1 = num1.try_into()
41 .unwrap()
42 .trailing_zeros() as usize;
43
44 let twos_num2 = num2.try_into()
45 .unwrap()
46 .trailing_zeros() as usize;
47
48 num1 >>= T::try_from(twos_num1).unwrap();
49 num2 >>= T::try_from(twos_num2).unwrap();
50
51 min(twos_num1, twos_num2)
52 };
53
54 loop {
55 if num1 > num2 {
56 swap(&mut num1, &mut num2);
57 }
58
59 num2 -= num1;
60
61 if num2.try_into().unwrap() == 0 {
62 num1 <<= T::try_from(min_twos).unwrap();
63 return num1;
64 }
65
66 num1 >>= T::try_from(num1.try_into()
67 .unwrap()
68 .trailing_zeros() as usize)
69 .unwrap();
70 }
71}