[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
|
---|
| 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
|
---|