source: Sophya/trunk/SophyaLib/BaseTools/pqnumber.cc@ 4069

Last change on this file since 4069 was 4062, checked in by ansari, 13 years ago

Petites ameliorations classes Units et PhysQty, documentation doxygen, ajout fichiers pqnumber.h et sunitpcst.h ds basetools.h, passage numero de version a 2.30, Reza 27/04/2012

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