1 | #include "machdefs.h"
|
---|
2 | #include <stdio.h>
|
---|
3 | #include "pqnumber.h"
|
---|
4 | #include "pexceptions.h"
|
---|
5 | #include "thsafeop.h" // for ThreadSafe operations (Ref.Count/Share)
|
---|
6 | #include <iostream>
|
---|
7 |
|
---|
8 | namespace SOPHYA {
|
---|
9 |
|
---|
10 | /*!
|
---|
11 | \class PrimeNumbers
|
---|
12 | \ingroup BaseTools
|
---|
13 | A simple class for class for manipulating prime naumbers. This class is thread safe
|
---|
14 |
|
---|
15 | \code
|
---|
16 | // Create a PrimeNumbers object
|
---|
17 | PrimeNumbers primes;
|
---|
18 | // Print the first 15 primes ...
|
---|
19 | for(size_t k=0; k<15; k++)
|
---|
20 | cout << primes(k) << endl;
|
---|
21 | // Print all prime numbers less than some max values
|
---|
22 | uint_8 pmax = 223;
|
---|
23 | uint_8 p = primes.Next();
|
---|
24 | while (p<pmax) {
|
---|
25 | cout << p << endl;
|
---|
26 | p = primes.Next();
|
---|
27 | }
|
---|
28 | \endcode
|
---|
29 | */
|
---|
30 |
|
---|
31 |
|
---|
32 | //--------------------- Classe PrimeNumbers ------------------------
|
---|
33 | static ThSafeOp* primes_gThsop = NULL; // Mutex global pour thread-safety
|
---|
34 | std::vector<uint_8> * PrimeNumbers::prime_list_p_ = NULL; // global prime number list
|
---|
35 |
|
---|
36 | /* --Methode-- */
|
---|
37 | PrimeNumbers::PrimeNumbers()
|
---|
38 | : my_prime_idx_(0)
|
---|
39 | {
|
---|
40 | Init();
|
---|
41 | }
|
---|
42 |
|
---|
43 | /* --Methode-- */
|
---|
44 | PrimeNumbers::PrimeNumbers(PrimeNumbers const& p)
|
---|
45 | : my_prime_idx_(p.my_prime_idx_)
|
---|
46 | {
|
---|
47 | Init();
|
---|
48 | }
|
---|
49 |
|
---|
50 |
|
---|
51 | /* --Methode-- */
|
---|
52 | uint_8 PrimeNumbers::Get(size_t k) const
|
---|
53 | {
|
---|
54 | uint_8 rp=2;
|
---|
55 | while (k>=prime_list_p_->size()) {
|
---|
56 | size_t nxt=k-prime_list_p_->size()+1;
|
---|
57 | if ((nxt<5)||(nxt < prime_list_p_->size()/16)) Extend(nxt);
|
---|
58 | else {
|
---|
59 | double dnl,dnh;
|
---|
60 | if (k<40000) encadre6(k, dnl,dnh);
|
---|
61 | else encadre40k(k, dnl,dnh);
|
---|
62 | uint_8 n = (uint_8)dnh+1;
|
---|
63 | //DBG cout << " DBG*PrimeNumbers::Get(" << k << ") dnh=" << dnh << " ->int=" << n << " nxt=" << nxt << endl;
|
---|
64 | Extend2(n);
|
---|
65 | }
|
---|
66 | }
|
---|
67 | rp= prime_list_p_->at(k);
|
---|
68 | return(rp);
|
---|
69 | }
|
---|
70 |
|
---|
71 | /* --Methode-- */
|
---|
72 | bool PrimeNumbers::CheckIfPrim(uint_8 n)
|
---|
73 | {
|
---|
74 | if (n<4) return true;
|
---|
75 | // On verifie et etend la liste des nombres premiers si besoin
|
---|
76 | uint_8 pe=prime_list_p_->at(prime_list_p_->size()-1);
|
---|
77 | while (pe*pe<(n+1)) {
|
---|
78 | uint_8 pet=pe;
|
---|
79 | while (pet*pet<(n+1)) pet+=pe/4;
|
---|
80 | Extend2(pet);
|
---|
81 | pe=prime_list_p_->at(prime_list_p_->size()-1);
|
---|
82 | }
|
---|
83 | // On verifie si n est premier
|
---|
84 | PrimeNumbers primes;
|
---|
85 | uint_8 p=primes.Next();
|
---|
86 | while (p*p<=n) {
|
---|
87 | if (n%p==0) return false;
|
---|
88 | p=primes.Next();
|
---|
89 | }
|
---|
90 | return true;
|
---|
91 | }
|
---|
92 |
|
---|
93 | /* --Methode-- */
|
---|
94 | vector<uint_8> PrimeNumbers::PrimeFactors(uint_8 n, bool fgprt)
|
---|
95 | {
|
---|
96 | PrimeNumbers primes;
|
---|
97 | std::vector<uint_8> fact;
|
---|
98 | if (n<4) {
|
---|
99 | if (n==0) fact.push_back(0);
|
---|
100 | else if (n==1) fact.push_back(1);
|
---|
101 | else if (n==2) fact.push_back(2);
|
---|
102 | else fact.push_back(3);
|
---|
103 | if (fgprt) cout << " PrimeFactors(" << n << ")= " << fact[0] << endl;
|
---|
104 | return fact;
|
---|
105 | }
|
---|
106 | uint_8 n0=n;
|
---|
107 | uint_8 p=primes.Next();
|
---|
108 | while(n>1) {
|
---|
109 | if (n%p==0) { fact.push_back(p); n/=p; }
|
---|
110 | else p=primes.Next();
|
---|
111 | }
|
---|
112 | if (fgprt) {
|
---|
113 | cout << " PrimeFactors(" << n0 << ")= " << fact[0];
|
---|
114 | if (fact.size()>1) {
|
---|
115 | for(size_t k=1; k<fact.size(); k++) {
|
---|
116 | cout << " x " << fact[k];
|
---|
117 | if (k%20==0) cout << "\n ... ";
|
---|
118 | }
|
---|
119 | }
|
---|
120 | cout << endl;
|
---|
121 | }
|
---|
122 | return fact;
|
---|
123 | }
|
---|
124 |
|
---|
125 | /* --Methode-- */
|
---|
126 | void PrimeNumbers::encadre6(size_t nieme,double &nlow,double &nhigh)
|
---|
127 | // encadrement du N-ieme (>=6) nombre premier
|
---|
128 | // warning: dump if n==1
|
---|
129 | {
|
---|
130 | double n = (double)nieme, ln = log(n), lln = log(log(n));
|
---|
131 | nlow = n * (ln + lln - 1.);
|
---|
132 | nhigh = n * (ln + lln);
|
---|
133 | return;
|
---|
134 | }
|
---|
135 |
|
---|
136 | /* --Methode-- */
|
---|
137 | void PrimeNumbers::encadre40k(size_t nieme,double &nlow,double &nhigh)
|
---|
138 | // encadrement du N-ieme (>=40000) nombre premier
|
---|
139 | // (rigoureusement nieme>=38691)
|
---|
140 | // warning: dump if n==1
|
---|
141 | {
|
---|
142 | double n = (double)nieme, ln = log(n), lln = log(log(n));
|
---|
143 | nlow = n * (ln + lln - 1.);
|
---|
144 | nhigh = n * (ln + lln - 0.948);
|
---|
145 | return;
|
---|
146 | }
|
---|
147 |
|
---|
148 | /* --Methode-- */
|
---|
149 | double PrimeNumbers::approx(unsigned int nieme)
|
---|
150 | // approximation du N-ieme
|
---|
151 | // warning: dump if n==1
|
---|
152 | {
|
---|
153 | double n = nieme, ln = log(n), lln = log(log(n));
|
---|
154 | return n * (ln + lln - 1. + (lln-2.)/ln);
|
---|
155 | }
|
---|
156 |
|
---|
157 | /* --Methode-- */
|
---|
158 | void PrimeNumbers::Init()
|
---|
159 | {
|
---|
160 | if (primes_gThsop != NULL) return;
|
---|
161 | primes_gThsop = new ThSafeOp;
|
---|
162 | primes_gThsop->lock();
|
---|
163 | prime_list_p_ = new std::vector<uint_8>(10,1);
|
---|
164 | uint_8 firstp[10]={2,3,5,7,11,13,17,19,23,29};
|
---|
165 | for(size_t k=0; k<10; k++) prime_list_p_->at(k)=firstp[k];
|
---|
166 | primes_gThsop->unlock();
|
---|
167 | return;
|
---|
168 | }
|
---|
169 |
|
---|
170 | /* --Methode-- */
|
---|
171 | void PrimeNumbers::Extend(size_t nxt)
|
---|
172 | {
|
---|
173 | primes_gThsop->lock();
|
---|
174 | //DBG cout << "\n DBG*Extend Sz=" << prime_list_p_->size() << " nxt= " << nxt << endl;
|
---|
175 |
|
---|
176 | for(size_t i=0; i<nxt; i++) {
|
---|
177 | uint_8 n = prime_list_p_->at(prime_list_p_->size()-1)+2;
|
---|
178 | bool fgp=false;
|
---|
179 | while(!fgp) {
|
---|
180 | fgp=CheckIfPrim_P(n);
|
---|
181 | if (fgp) { prime_list_p_->push_back(n); break; }
|
---|
182 | else n+=2;
|
---|
183 | }
|
---|
184 | }
|
---|
185 | primes_gThsop->unlock();
|
---|
186 | return;
|
---|
187 | }
|
---|
188 |
|
---|
189 | /* --Methode-- */
|
---|
190 | void PrimeNumbers::Extend2(uint_8 P)
|
---|
191 | {
|
---|
192 | uint_8 P0=prime_list_p_->at(prime_list_p_->size()-1);
|
---|
193 | if (P0>=P) return;
|
---|
194 | primes_gThsop->lock();
|
---|
195 | //DBG cout << "\n DBG*Extend2 Sz=" << prime_list_p_->size() << " P0=" << P0 << " ->P=" << P;
|
---|
196 | size_t npremiers;
|
---|
197 | unsigned char* liste=eratosthene(P,npremiers);
|
---|
198 | for(uint_8 i=P0+1; i<P; i+=2)
|
---|
199 | if (liste[i]) prime_list_p_->push_back(i+1);
|
---|
200 | delete[] liste;
|
---|
201 | //DBG cout << " NewSz=" << prime_list_p_->size() << " LastP=" << prime_list_p_->at(prime_list_p_->size()-1) << endl;
|
---|
202 | primes_gThsop->unlock();
|
---|
203 | return;
|
---|
204 | }
|
---|
205 |
|
---|
206 |
|
---|
207 | /* --Methode-- */
|
---|
208 | bool PrimeNumbers::CheckIfPrim_P(uint_8 n)
|
---|
209 | {
|
---|
210 | size_t k=0;
|
---|
211 | uint_8 p=prime_list_p_->at(k);
|
---|
212 | while (p*p<=n) {
|
---|
213 | if (n%p==0) return false;
|
---|
214 | k++; p=prime_list_p_->at(k);
|
---|
215 | }
|
---|
216 | return true;
|
---|
217 | }
|
---|
218 |
|
---|
219 |
|
---|
220 | /* --Methode-- */
|
---|
221 | unsigned char* PrimeNumbers::eratosthene(uint_8 P, size_t& npremiers)
|
---|
222 | /*
|
---|
223 | -- Le crible d'Eratosthene --
|
---|
224 | Trouver tous les nombres premiers inferieurs a un entier P
|
---|
225 | - Methode:
|
---|
226 | On ecrit tous les nombres de 1 a P
|
---|
227 | On elimine tous ceux qui sont divisibles par 2
|
---|
228 | On elimine tous ceux qui sont divisibles par 3
|
---|
229 | ...
|
---|
230 | Ainsi de suite pour tous les nombres les plus petits qui restent.
|
---|
231 | Les nombres successifs qui restent sont des nombres premiers.
|
---|
232 | - Implementation: routine eratosthene()
|
---|
233 | P : on cherche les nombres premiers <= P
|
---|
234 | liste : liste[i]=1 si "i+1" est un nombre premier
|
---|
235 | =0 sinon
|
---|
236 | Retourne le nombre de nombres premiers <= P
|
---|
237 | Attention "liste" est alloue par la routine eratosthene
|
---|
238 | et doit etre detruite par le programme appelant
|
---|
239 | */
|
---|
240 | {
|
---|
241 | uint_8 i,j,p,pp;
|
---|
242 | npremiers=0;
|
---|
243 | unsigned char* liste = new unsigned char[P];
|
---|
244 | for(i=0;i<P;i++) liste[i]=1;
|
---|
245 |
|
---|
246 | npremiers = 1;
|
---|
247 | for(i=1;i<P;i++) {
|
---|
248 | // On teste la primarite du nombre "p" = "i+1"
|
---|
249 | p = i+1;
|
---|
250 | /* printf("test i=%llu p=%llu liste[i]=%d\n",i,p,(*liste)[i]); */
|
---|
251 | if(liste[i]==0) continue;
|
---|
252 | npremiers++; pp=2*p; j=pp-1;
|
---|
253 | while(j<P) {
|
---|
254 | /* printf(" kill j=%llu pp=%llu\n",j,pp); */
|
---|
255 | liste[j]=0;
|
---|
256 | pp+=p; j=pp-1;
|
---|
257 | }
|
---|
258 | }
|
---|
259 | return liste;
|
---|
260 | }
|
---|
261 |
|
---|
262 | /*!
|
---|
263 | \class QNumber
|
---|
264 | \ingroup BaseTools
|
---|
265 | Class representing rational number (q \in Q). All operations are thread-safe.
|
---|
266 |
|
---|
267 | \code
|
---|
268 | // Create rational numbers from integers
|
---|
269 | QNumber q1(3,4), q2(5,6), q3(6,8);
|
---|
270 | // Operations and comparsion
|
---|
271 | QNumber q4 = q1+q2;
|
---|
272 | cout << q1 << " + " << q2 << " = " << q4 << endl;
|
---|
273 | QNumber qa(q1), qb(q2);
|
---|
274 | cout " Test qa==qb : -> " << qa << " ?== " << qb;
|
---|
275 | if (qa == qb) cout << " -> true " << endl;
|
---|
276 | else cout << " -> false " << endl;
|
---|
277 | qb = q3;
|
---|
278 | cout " Test qa==qb : -> " << qa << " ?== " << qb;
|
---|
279 | if (qa == qb) cout << " -> true " << endl;
|
---|
280 | else cout << " -> false " << endl;
|
---|
281 | QNumber qq(3*7*17*5,(-5)*7*11*2);
|
---|
282 | cout << " qq= " << qq << " qq.Simplify() = " << qq.Simplify() << endl;
|
---|
283 | \endcode
|
---|
284 | */
|
---|
285 |
|
---|
286 | /* --Methode-- */
|
---|
287 | QNumber QNumber::Simplify() const
|
---|
288 | {
|
---|
289 | if (num_==den_) return QNumber(1);
|
---|
290 | if (num_==(-den_)) return QNumber(-1);
|
---|
291 | uint_8 m=(num_>0)?(uint_8)num_:(uint_8)(-num_);
|
---|
292 | uint_8 n=(den_>0)?(uint_8)den_:(uint_8)(-den_);
|
---|
293 | QNumber qs=*this;
|
---|
294 | PrimeNumbers primes;
|
---|
295 | uint_8 p=primes.Next();
|
---|
296 | uint_8 petit=(m<n)?m:n;
|
---|
297 | while (p*p<=petit) {
|
---|
298 | if ((m%p==0)&&(n%p==0)) { m/=p; n/=p; }
|
---|
299 | else p=primes.Next();
|
---|
300 | }
|
---|
301 | int_8 nu=(int_8)m;
|
---|
302 | int_8 de=(int_8)n;
|
---|
303 | if (num_<0) nu= -nu;
|
---|
304 | if (den_<0) de= -de;
|
---|
305 | return QNumber(nu,de);
|
---|
306 | }
|
---|
307 |
|
---|
308 | /* --Methode-- */
|
---|
309 | std::string QNumber::ToString()
|
---|
310 | {
|
---|
311 | char buff[128];
|
---|
312 | if (den_==1) sprintf(buff,"%ld",(long)num_);
|
---|
313 | else sprintf(buff,"(%ld/%ld)",(long)num_,long(den_));
|
---|
314 | return buff;
|
---|
315 | }
|
---|
316 |
|
---|
317 | /* --Methode-- */
|
---|
318 | QNumber QNumber::Add(QNumber const & a, QNumber const & b, bool fgsimp)
|
---|
319 | {
|
---|
320 | QNumber rq=QNumber(a.num_*b.den_+b.num_*a.den_, a.den_*b.den_);
|
---|
321 | if (fgsimp) return rq.Simplify();
|
---|
322 | else return rq;
|
---|
323 | }
|
---|
324 |
|
---|
325 | /* --Methode-- */
|
---|
326 | QNumber QNumber::Subtract(QNumber const & a, QNumber const & b, bool fgsimp)
|
---|
327 | {
|
---|
328 | QNumber rq=QNumber(a.num_*b.den_-b.num_*a.den_, a.den_*b.den_);
|
---|
329 | if (fgsimp) return rq.Simplify();
|
---|
330 | else return rq;
|
---|
331 | }
|
---|
332 |
|
---|
333 | /* --Methode-- */
|
---|
334 | QNumber QNumber::Multiply(QNumber const & a, QNumber const & b, bool fgsimp)
|
---|
335 | {
|
---|
336 | QNumber rq=QNumber(a.num_*b.num_, a.den_*b.den_);
|
---|
337 | if (fgsimp) return rq.Simplify();
|
---|
338 | else return rq;
|
---|
339 | }
|
---|
340 |
|
---|
341 | /* --Methode-- */
|
---|
342 | QNumber QNumber::Divide(QNumber const & a, QNumber const & b, bool fgsimp)
|
---|
343 | {
|
---|
344 | if (b.num_==0) throw MathExc("QNumber::Divide(a,b) b=0->divide by zero");
|
---|
345 | QNumber rq=QNumber(a.num_*b.den_, a.den_*b.num_);
|
---|
346 | if (fgsimp) return rq.Simplify();
|
---|
347 | else return rq;
|
---|
348 | }
|
---|
349 |
|
---|
350 |
|
---|
351 |
|
---|
352 | /* --Methode-- */
|
---|
353 | int QNumber::Compare(QNumber const & a, QNumber const & b)
|
---|
354 | {
|
---|
355 | QNumber diff=a-b;
|
---|
356 | if (diff.Numerator()==0) return 0;
|
---|
357 | else if (diff.Numerator()>0) return 1;
|
---|
358 | else return -1;
|
---|
359 | }
|
---|
360 |
|
---|
361 |
|
---|
362 | } // FIN namespace SOPHYA
|
---|