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

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

Ajout fichiers pqnumber.h .cc et sunits.h .cc : classes PrimeNumbers , QNumber , Units , PhysQty - MAJ Makefile, sophyainit et numero de version SOPHYA a 2.222 V_Avr12, Reza 16/04/2012

File size: 9.2 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 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 ------------------------
33static ThSafeOp* primes_gThsop = NULL; // Mutex global pour thread-safety
34std::vector<uint_8> * PrimeNumbers::prime_list_p_ = NULL; // global prime number list
35
36/* --Methode-- */
37PrimeNumbers::PrimeNumbers()
38 : my_prime_idx_(0)
39{
40 Init();
41}
42
43/* --Methode-- */
44PrimeNumbers::PrimeNumbers(PrimeNumbers const& p)
45 : my_prime_idx_(p.my_prime_idx_)
46{
47 Init();
48}
49
50
51/* --Methode-- */
52uint_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-- */
72bool 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-- */
94vector<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-- */
126void 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-- */
137void 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-- */
149double 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-- */
158void 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-- */
171void 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-- */
190void 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-- */
208bool 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-- */
221unsigned 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-- */
287QNumber 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-- */
309std::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-- */
318QNumber 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-- */
326QNumber 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-- */
334QNumber 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-- */
342QNumber 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-- */
353int 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
Note: See TracBrowser for help on using the repository browser.