[4056] | 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
|
---|
[4062] | 17 | // Create a PrimeNumbers object
|
---|
[4056] | 18 | PrimeNumbers primes;
|
---|
[4062] | 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) << " ";
|
---|
[4056] | 22 | // Print all prime numbers less than some max values
|
---|
[4062] | 23 | uint_8 p = primes.Next(); uint_8 pmax = 223;
|
---|
| 24 | cout << endl << " Primes < " << pmax << " : " << endl;
|
---|
[4056] | 25 | while (p<pmax) {
|
---|
[4062] | 26 | cout << p << " ";
|
---|
| 27 | p = primes.Next();
|
---|
[4056] | 28 | }
|
---|
[4062] | 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;
|
---|
[4056] | 36 | \endcode
|
---|
| 37 | */
|
---|
| 38 |
|
---|
| 39 |
|
---|
| 40 | //--------------------- Classe PrimeNumbers ------------------------
|
---|
| 41 | static ThSafeOp* primes_gThsop = NULL; // Mutex global pour thread-safety
|
---|
| 42 | std::vector<uint_8> * PrimeNumbers::prime_list_p_ = NULL; // global prime number list
|
---|
| 43 |
|
---|
| 44 | /* --Methode-- */
|
---|
| 45 | PrimeNumbers::PrimeNumbers()
|
---|
| 46 | : my_prime_idx_(0)
|
---|
| 47 | {
|
---|
| 48 | Init();
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | /* --Methode-- */
|
---|
| 52 | PrimeNumbers::PrimeNumbers(PrimeNumbers const& p)
|
---|
| 53 | : my_prime_idx_(p.my_prime_idx_)
|
---|
| 54 | {
|
---|
| 55 | Init();
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 |
|
---|
| 59 | /* --Methode-- */
|
---|
| 60 | uint_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-- */
|
---|
| 80 | bool 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-- */
|
---|
| 102 | vector<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-- */
|
---|
| 134 | void 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-- */
|
---|
| 145 | void 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-- */
|
---|
| 157 | double 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-- */
|
---|
| 166 | void 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-- */
|
---|
| 179 | void 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-- */
|
---|
| 198 | void 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-- */
|
---|
| 216 | bool 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-- */
|
---|
| 229 | unsigned 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
|
---|
[4062] | 276 | // Create rational numbers from pairs of integers
|
---|
[4056] | 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);
|
---|
[4062] | 282 | cout << " Test qa==qb : -> " << qa << " ?== " << qb;
|
---|
[4056] | 283 | if (qa == qb) cout << " -> true " << endl;
|
---|
| 284 | else cout << " -> false " << endl;
|
---|
| 285 | qb = q3;
|
---|
[4062] | 286 | cout << " Test qa==qb : -> " << qa << " ?== " << qb;
|
---|
[4056] | 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-- */
|
---|
| 295 | QNumber 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-- */
|
---|
| 317 | std::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-- */
|
---|
| 326 | QNumber 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-- */
|
---|
| 334 | QNumber 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-- */
|
---|
| 342 | QNumber 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-- */
|
---|
| 350 | QNumber 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-- */
|
---|
| 361 | int 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
|
---|