OKlibrary
0.2.1.6
|
00001 // Oliver Kullmann, 6.11.2004 (Swansea) 00002 /* Copyright 2004 - 2007 Oliver Kullmann 00003 This file is part of the OKlibrary. OKlibrary is free software; you can redistribute 00004 it and/or modify it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation and included in this library; either version 3 of the 00006 License, or any later version. */ 00007 00014 #ifndef NUMBERTHEORYMODELS_66hdhsb2 00015 #define NUMBERTHEORYMODELS_66hdhsb2 00016 00017 #include <functional> 00018 #include <algorithm> 00019 #include <ostream> 00020 #include <string> 00021 #include <cassert> 00022 00023 #include <OKlib/General/Algebra_Traits.hpp> 00024 00025 namespace NumberTheory { 00026 00027 // ###################################################### 00028 00029 // Euclidian algorithm 00030 00031 template <typename Int> 00032 struct GcdVisitor_empty { 00033 void operator() (const Int&) {} 00034 void finished() {} 00035 }; 00036 template <typename Int> 00037 struct GcdVisitor_output { 00038 std::ostream& out; 00039 const std::string sep; 00040 GcdVisitor_output(std::ostream& out, const std::string& sep = ",") : out(out), sep(sep) {} 00041 void operator() (const Int& x) { 00042 out << x << sep; 00043 } 00044 void finished() { 00045 out << 0; 00046 } 00047 }; 00048 00049 template <typename Int, class Visitor = GcdVisitor_empty<Int> > 00050 struct Gcd : std::binary_function<Int, Int, Int> { 00051 typedef Int int_type; 00052 Visitor vis; 00053 Gcd() {} 00054 Gcd(Visitor vis) : vis(vis) {} 00055 int_type operator() (int_type a, int_type b) { 00056 vis(a); 00057 while (b != int_type(0)) { 00058 vis(b); 00059 a %= b; 00060 using std::swap; 00061 swap(a,b); 00062 } 00063 vis.finished(); 00064 return a; 00065 } 00066 }; 00067 00068 template <typename Int> 00069 inline Int gcd(const Int a, const Int b) { 00070 return Gcd<Int>()(a, b); 00071 } 00072 00073 // ###################### 00074 00075 // Extended Euclidian algorithm 00076 00077 template <typename Int> 00078 struct GcdExtVisitor_empty { 00079 void operator() (const Int&) {} 00080 void coefficients(const Int&, const Int&) {} 00081 void last_coefficients(const Int&, const Int&) {} 00082 void finished() {} 00083 }; 00084 template <typename Int> 00085 struct GcdExtVisitor_output { 00086 std::ostream& out_euc_seq; 00087 std::ostream& out_euc_ext_seq; 00088 const std::string sep; 00089 GcdExtVisitor_output(std::ostream& out1, std::ostream& out2, const std::string& sep = ",") : out_euc_seq(out1), out_euc_ext_seq(out2), sep(sep) {} 00090 void operator() (const Int& a) { 00091 out_euc_seq << a << sep; 00092 } 00093 void coefficients(const Int& x, const Int& y) { 00094 out_euc_ext_seq << "(" << x << "," << y << ")" << sep; 00095 } 00096 void last_coefficients(const Int& x, const Int& y) { 00097 out_euc_ext_seq << "(" << x << "," << y << ")"; 00098 } 00099 void finished() { 00100 out_euc_seq << 0; 00101 } 00102 }; 00103 00104 template <typename Int, class Visitor = GcdExtVisitor_empty<Int> > 00105 struct Gcd_extended : std::binary_function<Int, Int, Algebra_Traits::BinaryLinearCombination<Int, Int> > { 00106 00107 typedef Int int_type; 00108 typedef typename std::binary_function<int_type,int_type,Algebra_Traits::BinaryLinearCombination<int_type, int_type> >::result_type result_type; 00109 00110 Visitor vis; 00111 00112 Gcd_extended() {} 00113 Gcd_extended(Visitor vis) : vis(vis) {} 00114 00115 result_type operator() (const int_type a, const int_type b) { 00116 // TO IMPROVE: Using a fixed size vector class 00117 int_type a0(a), a1(b); 00118 vis(a0); 00119 int_type x0(int_type(1)), y0(int_type(0)), x1(int_type(0)), y1(int_type(1)); 00120 vis.coefficients(x0, y0); 00121 assert(a0 == x0 * a + y0 * b); 00122 assert(a1 == x1 * a + y1 * b); 00123 while (a1 != int_type(0)) { 00124 vis(a1); 00125 const int_type div = a0 / a1; 00126 using std::swap; 00127 x0 = x0 - div * x1; y0 = y0 - div * y1; 00128 swap(x0, x1); swap(y0, y1); 00129 vis.coefficients(x0, y0); 00130 a0 -= div * a1; 00131 swap(a0, a1); 00132 assert(a0 == x0 * a + y0 * b); 00133 assert(a1 == x1 * a + y1 * b); 00134 } 00135 vis.last_coefficients(x1, y1); 00136 vis.finished(); 00137 return result_type(x0, y0, a, b, a0); 00138 } 00139 }; 00140 00141 template <typename Int> 00142 inline Algebra_Traits::BinaryLinearCombination<Int, Int> gcd_extended(const Int a, const Int b) { 00143 return Gcd_extended<Int>()(a, b); 00144 } 00145 00146 // ###################################################### 00147 00148 // Euler's phi function 00149 template <typename Int> 00150 struct Euler_phi_brute_force : std::unary_function<Int, Int> { 00151 Int operator() (const Int n) const { 00152 assert(n >= 0); 00153 if (n == Int(0)) return Int(0); 00154 Int counter(Int(0)); 00155 for (Int i = 2; i < n; ++i) 00156 if (gcd(i, n) == Int(1)) ++counter; 00157 return counter + Int(1); 00158 } 00159 }; 00160 template <typename Int> 00161 inline Int euler_phi_brute_force(const Int n) { 00162 return Euler_phi_brute_force<Int>()(n); 00163 } 00164 } 00165 00166 #endif