C++ Library Extensions 2022.12.09
To help learn modern C++ programming
tpf_euclidean.hpp
Go to the documentation of this file.
1
11#ifndef _TPF_EUCLIDEAN_HPP
12#define _TPF_EUCLIDEAN_HPP
13
14#ifndef NOMINMAX
15#define NOMINMAX
16#endif
17
18#ifdef _MSVC_LANG
19 #if _MSVC_LANG < 201703L
20 #error This libary requires C++17 Standard (Visual Studio 2017).
21 #endif
22#else
23
24 #if __cplusplus < 201703
25 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
26 #endif // end of __cplusplus
27
28#endif // end of _MSVC_LANG
29
30#include <tpf_types.hpp>
31#include <utility>
32
37namespace tpf
38{
43 namespace euclidean
44 {
45 using namespace types;
46
47 // greatest common divisor
48 template<typename Type>
50 gcd(Type a, Type b)
51 {
52 Type r; // remainder
53 while(r = a % b)
54 {
55 a = b; b = r;
56 }
57
58 return b;
59 }
60
61 template<template<typename, typename...> class ContainerType, typename EleType>
62 enable_if_in_list_t<EleType, integral_list_t>
63 gcd(const ContainerType<EleType>& container)
64 {
65 if(container.empty())
66 return 1;
67 else
68 {
69 size_t size = container.size();
70
71 if(size==1)
72 return container.front();
73 else if(size==2)
74 return gcd(container[0], container[1]);
75 else
76 {
77 auto g = gcd(container[0], container[1]);
78 for(size_t i=2; i < size; ++i)
79 g = gcd(g, container[i]);
80
81 return g;
82 }
83 }
84 }
85
86 template<typename Type, typename... Types>
87 auto gcd(Type arg, Types... args)
88 {
89 return gcd(arg, gcd(args...));
90 }
91
92 // least common multiple
93 template<typename Type>
94 enable_if_in_list_t<Type, integral_list_t>
95 lcm(Type a, Type b)
96 {
97 return (a / gcd(a, b)) * b;
98 }
99
100 template<typename Type, typename... Types>
101 auto lcm(Type arg, Types... args)
102 {
103 return lcm(arg, lcm(args...));
104 }
105
106 template<template<typename, typename...> class ContainerType, typename EleType>
107 enable_if_in_list_t<EleType, integral_list_t>
108 lcm(const ContainerType<EleType>& container)
109 {
110 if(container.empty())
111 return 1;
112 else
113 {
114 size_t size = container.size();
115
116 if(size==1)
117 return container.front();
118 else if(size==2)
119 return lcm(container[0], container[1]);
120 else
121 {
122 auto l = lcm(container[0], container[1]);
123
124 for(size_t i=2; i < size; ++i)
125 l = lcm(l, container[i]);
126
127 return l;
128 }
129 }
130 }
131
132 template<typename Type>
133 enable_if_in_list_t<Type, integral_list_t, void>
134 reduce(Type& a, Type& b)
135 {
136 auto g = gcd(a, b);
137 a /= g; b /= g;
138 }
139
140 namespace hidden
141 {
142 // https://goo.gl/o1mKYM
143 // https://goo.gl/NTdu2w
144 // a * x + b * y = gcd(a , b)
145 // eea for Extended Euclidean Algorithm
146 // do not call it directly,
147 // it is helper function
148 //
149 // precondition: a > b, otherwise
150 // if (b > a) std::swap(a, b);
151 // if fails, return 0;
152 template<typename Type>
153 Type extended_euclidean_algorithm(Type a, Type b, Type& x, Type& y)
154 {
155 std::vector<Type> q; q.reserve(100);
156
157 Type r; // remainder
158
159 while (r = a % b)
160 {
161 q.emplace_back(-(a / b));
162 a = b; b = r;
163 }
164
165 // 10 x + 5 y = gcd(10, 5) = 5
166 // if gcd != 1, then we cannot solve
167 // 10 x = 1 (mod 5) or 5 x = 1 (mod 10)
168 // 10 x + 5 y = 5
169 // 10 0 + 5 1 = 5
170 // x = 0, y = 1
171 if (q.empty())
172 {
173 x = 0; y = 1; return b;
174 }
175
176 // initial condition
177 x = 1; y = q.back();
178 size_t cache_count = q.size();
179
180 for (size_t i = cache_count - 2; i != 0; --i)
181 {
182 Type tmp = x; x = y; y = tmp + y*q[i];
183 }
184
185 if(cache_count>1)
186 {
187 Type tmp = x; x = y; y = tmp + y*q[0];
188 }
189
190 return b;
191 }
192 } // end of namespace hidden
193
194 // https://goo.gl/o1mKYM
195 // https://goo.gl/NTdu2w
196 // a x + b y = gcd(a, b)
197 // return gcd(a, b), x and y
198 template<typename Type>
199 Type extended_euclidean_algorithm(Type a, Type b, Type& x, Type& y)
200 {
201 Type a1 = a, b1 = b;
202
203 // remember we have swapped a and b
204 if (b1 > a1) std::swap(a1, b1);
205
207
208 // if x and y does not satisfy
209 // a * x + b * y = gcd(a, b), i.e.,
210 // a * x + b * y != gcd(a, b)
211 // then we have to swap x and y
212 if (a * x + b * y != g)
213 std::swap(x, y);
214
215 return g;
216 }
217
218 } // end of namespace set
219
220} // end of namespace euclidean
221
222#endif // end of file _TPF_EUCLIDEAN_HPP
Type extended_euclidean_algorithm(Type a, Type b, Type &x, Type &y)
enable_if_in_list_t< Type, integral_list_t, void > reduce(Type &a, Type &b)
Type extended_euclidean_algorithm(Type a, Type b, Type &x, Type &y)
enable_if_in_list_t< Type, integral_list_t > lcm(Type a, Type b)
enable_if_in_list_t< Type, integral_list_t > gcd(Type a, Type b)
Type to string name conversions are defined.
Definition: 31-visit.cpp:7
hidden::enable_if_in_list_t< TestType, TypeList, ReturnType > enable_if_in_list_t
Definition: tpf_types.hpp:6406
Includes subnamespace conversion.
Definition: 31-visit.cpp:7
Type functions are implemented.