00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef GUAR_EXACT_H
00021 #define GUAR_EXACT_H
00022
00023 #include <math.h>
00024
00025
00026 namespace guar {
00027
00028 using gul::Assert;
00029 using gul::InternalError;
00030 using gul::ndebug;
00031 using gul::Swap;
00032
00033
00034
00035
00036
00037 template< class T >
00038 void IntTo( const unsigned int na, const unsigned long *a, T& t )
00039 {
00040 int i;
00041
00042 if( na == 0 )
00043 {
00044 t = (T)0.0;
00045 return;
00046 }
00047 t = (T)a[na-1];
00048
00049 for( i = na-2; i >= 0; i-- )
00050 {
00051 t = t*(T)(LL(0x100000000)) + (T)a[i];
00052 }
00053 }
00054
00055
00056
00057
00058 void IntAdd( const unsigned int na, const unsigned long *a,
00059 const unsigned int nb, const unsigned long *b,
00060 unsigned int *nc, unsigned long *c );
00061
00062
00063
00064
00065
00066
00067 int IntSub( const int unsigned na, const unsigned long *a,
00068 const int unsigned nb, const unsigned long *b,
00069 unsigned int *nc, unsigned long *c );
00070
00071
00072
00073
00074 unsigned long IntMultShort(
00075 const unsigned int na, const unsigned long *a, const unsigned long b,
00076 unsigned long *c );
00077
00078
00079
00080
00081
00082 void IntMult( const unsigned int na, const unsigned long *a,
00083 const unsigned int nb, const unsigned long *b,
00084 unsigned int *nc, unsigned long *c );
00085
00086
00087
00088
00089 unsigned long IntDivShort(
00090 const unsigned int na, const unsigned long *a, const unsigned long b,
00091 unsigned int *nq, unsigned long *q );
00092
00093
00094
00095
00096 int IntDiv( const unsigned int na, const unsigned long *a,
00097 const unsigned int nb, const unsigned long *b,
00098 unsigned int *nq, unsigned long *q,
00099 unsigned int *nr, unsigned long *r );
00100
00101
00102
00103
00104 int DoubleToInt( const double d, const unsigned int na, unsigned long *a,
00105 unsigned int *retLen );
00106
00107
00108
00109
00110 double IntToDouble( const unsigned int na, const unsigned long *a );
00111
00112
00113
00114
00115 struct Interval
00116 {
00117 friend Interval operator+( const Interval &a, const Interval &b );
00118 friend Interval operator-( const Interval &a, const Interval &b );
00119 friend Interval operator*( const Interval &a, const Interval &b );
00120 friend Interval operator/( const Interval &a, const Interval &b );
00121 friend int Test( const Interval &a, const Interval &b );
00122
00123 double m_low;
00124 double m_high;
00125
00126 Interval() { m_low = 0.0; m_high = 0.0; }
00127 Interval(double val) { m_low = val; m_high = val; }
00128 Interval(double low, double high) { m_low = low; m_high = high; }
00129 };
00130
00131
00132
00133
00134
00135 class ULong
00136 {
00137 unsigned long l;
00138 public:
00139 explicit ULong( unsigned long ul ) : l(ul) { }
00140 operator unsigned long() const { return l; }
00141 };
00142
00143
00144
00145 class rational
00146 {
00147 public:
00148 struct rational_rep
00149 {
00150 unsigned int m_na;
00151 unsigned long *m_a;
00152
00153 unsigned int m_nb;
00154 unsigned long *m_b;
00155
00156 size_t m_size_a;
00157 size_t m_size_b;
00158
00159 int m_refcount;
00160
00161 Interval m_i;
00162
00163 int m_sign : 2;
00164 unsigned int m_bounds : 1;
00165
00166 rational_rep()
00167 {
00168 m_refcount = 1;
00169 m_sign = 0;
00170 m_bounds = m_na = m_nb = 0;
00171 m_size_a = m_size_b = 0;
00172 m_a = m_b = NULL;
00173 }
00174
00175 rational_rep( int sign, int na, unsigned long *a )
00176 {
00177 size_t bsize;
00178
00179 m_refcount = 1;
00180 m_sign = 0;
00181 m_bounds = m_na = m_nb = 0;
00182 m_size_b = m_size_a = 0;
00183 m_a = m_b = 0;
00184
00185 if( na == 0 ) return;
00186
00187 m_a = (unsigned long *)gust::PoolAlloc( na*sizeof(unsigned long), &bsize );
00188 if( m_a == NULL ) throw gul::PoolAllocError();
00189 for( int i=0; i<na; i++ ) m_a[i] = a[i];
00190
00191 m_sign = sign;
00192 m_na = na;
00193 m_size_a = bsize;
00194 }
00195
00196 rational_rep( int sign, unsigned long a )
00197 {
00198 size_t bsize;
00199
00200 m_refcount = 1;
00201 m_sign = 0;
00202 m_bounds = m_na = m_nb = 0;
00203 m_size_a = m_size_b = 0;
00204 m_a = m_b = NULL;
00205 if( a == 0 ) return;
00206
00207 m_a = (unsigned long *)gust::PoolAlloc( sizeof(unsigned long), &bsize );
00208 if( m_a == NULL ) throw gul::PoolAllocError();
00209 m_a[0] = a;
00210
00211 m_sign = sign;
00212 m_na = 1;
00213 m_size_a = bsize;
00214 }
00215
00216
00217 rational_rep( int sign, int na, int nb )
00218 {
00219 size_t bsize;
00220
00221 m_refcount = 1;
00222 m_sign = 0;
00223 m_bounds = m_na = m_nb = 0;
00224 m_size_a = m_size_b = 0;
00225 m_a = m_b = NULL;
00226
00227 if( na != 0 )
00228 {
00229 m_sign = sign;
00230 m_a = (unsigned long *)gust::PoolAlloc( na*sizeof(unsigned long),&bsize);
00231 if( m_a == NULL ) throw gul::PoolAllocError();
00232 m_size_a = bsize;
00233 m_na = na;
00234 }
00235 if( nb != 0 )
00236 {
00237 m_b = (unsigned long *)gust::PoolAlloc( nb*sizeof(unsigned long),&bsize);
00238 if( m_b == NULL ) throw gul::PoolAllocError();
00239 m_size_b = bsize;
00240 m_nb = nb;
00241 }
00242 }
00243
00244 ~rational_rep()
00245 {
00246 if( (m_size_a != 0) && (m_a != NULL) ) gust::PoolFree( m_a, m_size_a );
00247 if( (m_size_b != 0) && (m_b != NULL) ) gust::PoolFree( m_b, m_size_b );
00248 }
00249
00250 template< class T >
00251 void dump( T& num, T& den )
00252 {
00253 if( m_na == 0 )
00254 { num = (T)0.0; den = (T)1.0; return; }
00255 else
00256 IntTo<T>( m_na, m_a, num );
00257
00258 if( m_sign )
00259 num = -num;
00260
00261 if( m_nb == 0 )
00262 den = (T)1.0;
00263 else
00264 IntTo<T>( m_nb, m_b, den );
00265 }
00266
00267 void calc_bounds( void )
00268 {
00269 Interval inum,iden;
00270 double num,den;
00271
00272 dump( num, den );
00273 if( num != 0.0 )
00274 {
00275 inum.m_low = num - DBL_EPSILON*fabs(num);
00276 inum.m_high = num + DBL_EPSILON*fabs(num);
00277 }
00278 else
00279 {
00280 inum.m_low = inum.m_high = 0.0;
00281 }
00282
00283 if( den != 1.0 )
00284 {
00285 iden.m_low = den - DBL_EPSILON*fabs(den);
00286 iden.m_high = den + DBL_EPSILON*fabs(den);
00287 }
00288 else
00289 {
00290 iden.m_low = iden.m_high = 1.0;
00291 }
00292
00293 m_i = inum/iden;
00294
00295 m_bounds = 1;
00296 }
00297
00298 void negative( void )
00299 {
00300 if( m_na != 0 )
00301 m_sign ^= -1;
00302 }
00303
00304 void reciprocal( void )
00305 {
00306 size_t bsize;
00307 unsigned long *p;
00308 int i;
00309
00310 if( m_na == 0 ) throw gul::Error();
00311
00312 if( (m_na == 1) && (m_a[0] == 1) )
00313 {
00314 gust::PoolFree( m_a, m_size_a );
00315 m_na = 0;
00316 m_size_a = 0;
00317 m_a = NULL;
00318 }
00319
00320 if( m_size_b == 0 )
00321 {
00322 m_b = (unsigned long *)gust::PoolAlloc( sizeof(unsigned long), &bsize );
00323 if( m_b == NULL ) throw gul::PoolAllocError();
00324 m_nb = 1;
00325 m_b[0] = 1;
00326 m_size_b = bsize;
00327 }
00328
00329 i = m_na; m_na = m_nb; m_nb = i;
00330 bsize = m_size_a; m_size_a = m_size_b; m_size_b = bsize;
00331 p = m_a; m_a = m_b; m_b = p;
00332 }
00333 };
00334
00335 public:
00336 rational_rep *m;
00337
00338 GULAPI rational( void );
00339 GULAPI explicit rational( int na, unsigned long *a, int sign = 0 );
00340 GULAPI explicit rational( ULong a, int sign = 0 );
00341 GULAPI explicit rational( int sign, int size_a, int size_b );
00342
00343 rational( const rational& other )
00344 {
00345 other.m->m_refcount++;
00346 m = other.m;
00347 }
00348
00349 GULAPI rational& operator=( const rational& other );
00350 GULAPI ~rational();
00351
00352 GULAPI rational get_copy() const;
00353
00354 rational numerator() const
00355 {
00356 if( m->m_na )
00357 return rational(m->m_na,m->m_a,m->m_sign);
00358
00359 return rational();
00360 }
00361 rational denominator() const
00362 {
00363 if( m->m_nb )
00364 return rational(m->m_nb,m->m_b,m->m_sign);
00365
00366 return rational(ULong(1));
00367 }
00368
00369
00370 GULAPI void calc_bounds( void ) const;
00371 GULAPI const Interval& get_bounds( void ) const;
00372
00373 template< class T > GULAPI void dump( T& num, T& den ) const;
00374 template< class T > void dump( T& t ) const
00375 {
00376 T n,d;
00377
00378 m->dump( n, d );
00379
00380 t = n/d;
00381 }
00382 double dump() const
00383 {
00384 double t;
00385 dump(t);
00386 return t;
00387 }
00388
00389 bool is_zero( void ) const { return(m->m_na == 0); }
00390
00391 int test( void ) const
00392 {
00393 if( m->m_sign ) return(-1);
00394 else if( m->m_na == 0 ) return(0);
00395 return(1);
00396 }
00397
00398 GULAPI void div_mod( rational *q, rational *r ) const;
00399
00400 GULAPI friend rational operator*( const rational& a, const rational& b );
00401 GULAPI friend rational operator+( const rational& A, const rational& B );
00402 GULAPI friend rational operator/( const rational& A, const rational& B );
00403 GULAPI friend rational operator-( const rational& A, const rational& B );
00404
00405 };
00406
00407
00408
00409
00410
00411
00412
00413 inline Interval operator+( const Interval &a, const Interval &b )
00414 {
00415 Interval c;
00416
00417 c.m_low = a.m_low + b.m_low;
00418 c.m_low = c.m_low - DBL_EPSILON*fabs(c.m_low);
00419
00420 c.m_high = a.m_high + b.m_high;
00421 c.m_high = c.m_high + DBL_EPSILON*fabs(c.m_high);
00422
00423 return( c );
00424 }
00425
00426 inline Interval operator-( const Interval &a, const Interval &b )
00427 {
00428 Interval c(-b.m_high,-b.m_low);
00429
00430 return(a+c);
00431 }
00432
00433 inline Interval operator/( const Interval &a, const Interval &b )
00434 {
00435 if( (b.m_low < 0.0) && (b.m_high > 0.0) )
00436 throw gul::IntervalDivZeroError();
00437
00438 Interval c(1.0/b.m_high,1.0/b.m_low);
00439
00440 return(a*c);
00441 }
00442
00443
00444 inline Interval Sqrt( const Interval &a )
00445 {
00446 Interval c;
00447
00448 c.m_low = sqrt(a.m_low);
00449 c.m_low = c.m_low - DBL_EPSILON*fabs(c.m_low);
00450
00451 c.m_high = sqrt(a.m_high);
00452 c.m_high = c.m_high + DBL_EPSILON*fabs(c.m_high);
00453
00454 return( c );
00455 }
00456
00457 inline int Test( const Interval &a )
00458 {
00459 if( a.m_high < 0.0 ) return(-1);
00460 if( a.m_low > 0.0 ) return(+1);
00461
00462 return(0);
00463 }
00464
00465 inline int Test( const Interval &a, const Interval &b )
00466 {
00467 Interval c = a-b;
00468 return Test(c);
00469 }
00470
00471 inline double GetRatio( const Interval &a )
00472 {
00473 double h,l;
00474
00475 h = a.m_high;
00476 l = a.m_low;
00477
00478 if( l < 0.0 )
00479 {
00480 if( h >= 0.0 ) return gul::rtr<double>::giant();
00481
00482 h = -l;
00483 l = -h;
00484 }
00485
00486 if( l == 0.0 )
00487 {
00488 if( h == 0.0 ) return 1.0;
00489 return gul::rtr<double>::giant();
00490 }
00491
00492 return h/l;
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594 }
00595
00596 namespace gul {
00597
00598 template<> struct rtr< guar::rational >
00599 {
00600
00601
00602
00603
00604
00605 static guar::rational zero() { return guar::rational(); }
00606 static guar::rational one() { return guar::rational(guar::ULong(1)); }
00607 };
00608
00609 template<>
00610 inline int test( const guar::rational& a )
00611 {
00612 return a.test();
00613 }
00614
00615 #ifdef GUL_VECTOR_H
00616 template<> inline point<guar::rational> cross_product(
00617 const point2<guar::rational>& a, const point2<guar::rational>& b )
00618 {
00619 point<guar::rational> c;
00620 c.z = a.x*b.y-b.x*a.y;
00621 return c;
00622 }
00623 #endif
00624
00625 template<>
00626 inline int compare( const guar::rational& A, const guar::rational &B )
00627 {
00628 guar::Interval i;
00629
00630 if( A.m == B.m )
00631 return 0;
00632
00633 if( !A.m->m_bounds ) A.calc_bounds();
00634 if( !B.m->m_bounds ) B.calc_bounds();
00635 i = A.m->m_i - B.m->m_i;
00636 if( i.m_high < 0.0 ) return(-1);
00637 else if( i.m_low > 0.0 ) return(1);
00638
00639 guar::rational c = A - B;
00640 if( c.m->m_sign ) return(-1);
00641 if( c.m->m_na == 0 ) return(0);
00642
00643 return(1);
00644 }
00645
00646 inline std::ostream& operator<<( std::ostream& s, const guar::rational& r )
00647 {
00648 return s << r.dump();
00649 }
00650
00651 }
00652
00653 #endif