00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "config.hpp"
00018
00019 #if !defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE) || \
00020 defined(ARAGELI_INCLUDE_CPP_WITH_EXPORT_TEMPLATE_GCD)
00021
00022 #include <cstddef>
00023 #include <algorithm>
00024
00025 #include "gcd.hpp"
00026 #include "_utility.hpp"
00027
00028
00029 namespace Arageli
00030 {
00031
00032
00033 namespace _Internal
00034 {
00035
00036 template <typename T>
00037 inline T& euclid_norm (T& x) { return x; }
00038
00039 template <typename T, typename P, bool REFCNT>
00040 inline sparse_polynom<T, P, REFCNT>& euclid_norm (sparse_polynom<T, P, REFCNT>& x)
00041 {
00042 if(!is_null(x))x /= x.leading_coef_cpy();
00043 return x;
00044 }
00045
00046 template <typename T1, typename T2, typename T3>
00047 inline void euclid_norm (T1& x1, T2& x2, T3& x3) {}
00048
00049 template
00050 <
00051 typename T1, typename P1, bool REFCNT1,
00052 typename T2, typename P2, bool REFCNT2,
00053 typename T3, typename P3, bool REFCNT3
00054 >
00055 inline void euclid_norm
00056 (
00057 sparse_polynom<T1, P1, REFCNT1>& x1,
00058 sparse_polynom<T2, P2, REFCNT2>& x2,
00059 sparse_polynom<T3, P3, REFCNT3>& x3
00060 )
00061 {
00062 if(!is_null(x1))
00063 {
00064 x2 /= x1.leading_coef();
00065 x3 /= x1.leading_coef();
00066 x1 /= x1.leading_coef_cpy();
00067 }
00068 }
00069
00070 }
00071
00072
00073 template <typename T, typename T_factory>
00074 T euclid (T a, T b, const T_factory& tfctr)
00075 {
00076 if(is_negative(a))opposite(&a);
00077 if(is_negative(b))opposite(&b);
00078
00079 if(is_null(a))
00080 if(is_null(b))return tfctr.unit(a);
00081 else return _Internal::euclid_norm(b);
00082 if(is_null(b))return _Internal::euclid_norm(a);
00083
00084 while(!is_null(a %= b)){ std::swap(a, b); }
00085 return _Internal::euclid_norm(b);
00086 }
00087
00088
00089 template <typename T, typename T_factory>
00090 T euclid_binary (T a, T b, const T_factory& tfctr)
00091 {
00092 if(is_negative(a))opposite(&a);
00093 if(is_negative(b))opposite(&b);
00094
00095 if(is_null(a))
00096 if(is_null(b))return tfctr.unit(a);
00097 else return _Internal::euclid_norm(b);
00098 if(is_null(b))return _Internal::euclid_norm(a);
00099
00100 T res = tfctr.unit(a);
00101
00102 while(!is_unit(a) && !is_unit(b))
00103 {
00104 ARAGELI_ASSERT_1(!is_null(a));
00105 ARAGELI_ASSERT_1(!is_null(b));
00106
00107 if(is_even(a))
00108 if(is_even(b))
00109 {
00110 a >>= 1; b >>= 1;
00111 res <<= 1;
00112 }
00113 else
00114 {
00115 a >>= 1;
00116 }
00117 else
00118 if(is_even(b))
00119 {
00120 b >>= 1;
00121 }
00122 else
00123 {
00124 T t = a - b;
00125 switch(sign(t))
00126 {
00127 case +1:
00128 {
00129 a = t;
00130 a >>= 1;
00131 break;
00132 }
00133 case -1:
00134 {
00135 b = -t;
00136 b >>= 1;
00137 break;
00138 }
00139 case 0: return _Internal::euclid_norm(res *= a);
00140 }
00141 }
00142 }
00143
00144 return _Internal::euclid_norm(res);
00145 }
00146
00147
00148 template <typename T>
00149 T gcdex (const T& a, const T& b, T&u, T& v, T& w, T& z)
00150 {
00151 T g = euclid_bezout(a, b, u, v);
00152
00153 if(is_null(g))
00154 {
00155 u = unit(u);
00156 v = null(v);
00157 w = null(w);
00158 z = unit(z);
00159 return g;
00160 }
00161
00162 z = a/g; w = -b/g;
00163
00164 ARAGELI_ASSERT_1(is_unit(abs(u*z - w*v)));
00165 ARAGELI_ASSERT_1(is_null(a*w + b*z));
00166
00167 return g;
00168 }
00169
00170
00171 template <typename T>
00172 T gcdex (const T& a, const T& b, const T& N, T&u, T& v, T& w, T& z)
00173 {
00174 ARAGELI_ASSERT_0(is_positive(N));
00175
00176 T a_mod_N = mod(a, N),
00177 b_mod_N = mod(b, N),
00178 g = euclid_bezout(a_mod_N, b_mod_N, u, v);
00179
00180 if(is_null(g))
00181 {
00182 u = unit(u);
00183 v = null(v);
00184 w = null(w);
00185 z = unit(z);
00186
00187 return g;
00188 }
00189
00190 u = mod(u, N);
00191 v = mod(v, N);
00192 w = N - b_mod_N/g;
00193 z = a_mod_N/g;
00194
00195 ARAGELI_ASSERT_1(is_unit(gcd(mod(u*z - w*v, N), N)));
00196 ARAGELI_ASSERT_1(is_null(mod(a*w + b*z,N)));
00197
00198 return g;
00199 }
00200
00201
00202 template <typename T, bool REFCNT, typename T_factory>
00203 T gcd (const vector<T, REFCNT>& v, const T_factory& tfctr)
00204 {
00205 if(v.is_empty())return tfctr.null();
00206
00207 T d = v[v.size() - 1];
00208 typedef typename vector<T, REFCNT>::difference_type difftype;
00209 difftype j = difftype(v.size()) - 2;
00210
00211 while(!is_unit(d) && j >= 0)
00212 {
00213 if(!is_null(v[j]))
00214 d = gcd(v[j], d, tfctr);
00215 --j;
00216 }
00217
00218 return is_null(d) ? tfctr.unit() : d;
00219 }
00220
00221
00222 template <typename T, bool REFCNT, typename T_factory>
00223 T lcm (const vector<T, REFCNT>& v, const T_factory& tfctr)
00224 {
00225 if(v.is_empty())return tfctr.unit();
00226
00227 T d = v[v.size() - 1];
00228 typedef typename vector<T, REFCNT>::difference_type difftype;
00229 difftype j = difftype(v.size()) - 2;
00230
00231 while(j >= 0)
00232 {
00233 if(!is_null(v[j]))
00234 d = lcm(v[j], d, tfctr);
00235 --j;
00236 }
00237
00238 return is_null(d) ? tfctr.unit() : d;
00239 }
00240
00241
00242 template
00243 <
00244 typename T, bool REFCNT, typename T_factory,
00245 typename T1, bool REFCNT1
00246 >
00247 vector<T, REFCNT> gcd_vec
00248 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00249 {
00250 ARAGELI_ASSERT_0(a.size() == b.size());
00251 std::size_t size = a.size();
00252 vector<T, REFCNT> res(size, T());
00253
00254 for(std::size_t i = 0; i < size; ++i)
00255 res[i] = gcd(a[i], b[i]);
00256
00257 return res;
00258 }
00259
00260
00261 template
00262 <
00263 typename T, bool REFCNT, typename T_factory,
00264 typename T1, bool REFCNT1
00265 >
00266 vector<T, REFCNT> lcm_vec
00267 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00268 {
00269 ARAGELI_ASSERT_0(a.size() == b.size());
00270
00271 ARAGELI_ASSERT_0(a.size() == b.size());
00272 std::size_t size = a.size();
00273 vector<T, REFCNT> res(size, T());
00274
00275 for(std::size_t i = 0; i < size; ++i)
00276 res[i] = lcm(a[i], b[i]);
00277
00278 return res;
00279 }
00280
00281
00282 template
00283 <
00284 typename T, bool REFCNT, typename T_factory,
00285 typename T1, bool REFCNT1
00286 >
00287 vector<T, REFCNT> euclid
00288 (const vector<T, REFCNT>& a, const vector<T1, REFCNT1>& b, const T_factory& tfctr)
00289 {
00290 ARAGELI_ASSERT_0(a.size() == b.size());
00291
00292 std::size_t size = a.size();
00293 vector<T, REFCNT> res(size, T());
00294
00295 for(std::size_t i = 0; i < size; ++i)
00296 res[i] = euclid(a[i], _Internal::noncopy_cast(b[i]), tfctr);
00297
00298 return res;
00299 }
00300
00301
00302 template <typename T, typename T_factory>
00303 T euclid_bezout
00304 (
00305 const T& a, const T& b, T& u, T& v,
00306 const T_factory& tfctr
00307 )
00308 {
00309
00310
00311
00312
00313
00314 u = tfctr.unit(a);
00315 v = tfctr.null(a);
00316 T u_new = v;
00317 T v_new = u;
00318 T r = abs(a);
00319 T r_new = abs(b);
00320
00321 while(!is_null(r_new))
00322 {
00323 T q = prquot(r, r_new);
00324
00325 T aux = u_new;
00326 u_new = u - q * u_new;
00327 u = aux;
00328
00329 aux = v_new;
00330 v_new = v - q * v_new;
00331 v = aux;
00332
00333 aux = r_new;
00334 r_new = r - q * r_new;
00335 r = aux;
00336 }
00337
00338 if(is_negative(a))opposite(&u);
00339 if(is_negative(b))opposite(&v);
00340
00341
00342
00343
00344
00345
00346 _Internal::euclid_norm(r, u, v);
00347
00348
00349
00350
00351
00352
00353 ARAGELI_ASSERT_1(a*u + b*v == r);
00354
00355 return r;
00356 }
00357
00358
00359 }
00360
00361 #endif
00362