home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ledar34.zip / leda-r-3_4_tar / LEDA-3.4 / src / numbers / _rational.c < prev    next >
C/C++ Source or Header  |  1996-09-03  |  10KB  |  504 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA 3.4
  4. +
  5. +  _rational.c
  6. +
  7. +  This file is part of the LEDA research version (LEDA-R) that can be 
  8. +  used free of charge in academic research and teaching. Any commercial
  9. +  use of this software requires a license which is distributed by the
  10. +  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
  11. +  (fax +49 681 31104).
  12. +
  13. +  Copyright (c) 1991-1996  by  Max-Planck-Institut fuer Informatik
  14. +  Im Stadtwald, 66123 Saarbruecken, Germany     
  15. +  All rights reserved.
  16. *******************************************************************************/
  17. #include <LEDA/basic.h>
  18. #include <LEDA/rational.h>
  19. #include <math.h>
  20. #include <ctype.h>
  21.  
  22.  
  23. rational& rational::normalize()
  24.   // divide num and den by their gcd(num,den)
  25.   // precondition: den  > 0
  26.  
  27.   if (num == den) 
  28.     num = den = 1; 
  29.   else
  30.     if (-num == den) 
  31.       { num = -1; 
  32.         den = 1; 
  33.        }
  34.     else
  35.       { integer ggt = gcd(num, den);
  36.         if (ggt != 1) 
  37.         { num /= ggt;
  38.           den /= ggt;
  39.          }
  40.        }
  41.  
  42.   return *this;
  43. }
  44.  
  45.  
  46. rational& rational::simplify(const integer& a)
  47.   // divide num and den by a
  48.  
  49.   integer r;
  50.   den = den.div(a,r);
  51.  
  52.   if (r !=0)
  53.     error_handler(1,"rational::simplify: argument does not divide denominator");
  54.  
  55.   num = num.div(a,r);
  56.  
  57.   if (r !=0)
  58.     error_handler(1,"rational::simplify: argument does not divide numerator");
  59.  
  60.   return *this;
  61. }
  62.  
  63.  
  64.  
  65. // constructors
  66.  
  67. rational::rational(int n, int d)
  68.   if (d == 0) error_handler(1,"rational: Zero denominator!");
  69.  
  70.   if (d < 0) { n = -n; d = -d; }  //wegen reference counting notwendig
  71.  
  72.   num = integer(n); 
  73.   den = integer(d);
  74.  }
  75.  
  76.  
  77. rational::rational(integer n, integer d)
  78.   if (d.PTR->sign == 0) error_handler(1,"rational: Zero denominator!");
  79.  
  80.   if (d.PTR->sign == -1) 
  81.     { num = -n; den = -d; }
  82.   else
  83.     { num =  n; den =  d; }
  84. }
  85.  
  86.  
  87. rational::rational(double x)
  88.   { num = 0; 
  89.     den = 1;
  90.  
  91.     if (x != 0)
  92.     { int neg = (x < 0);
  93.       if (neg) x = -x;
  94.  
  95.       const unsigned shift = 15;   // a safe shift per step
  96.       const double width = 32768;  // = 2^shift
  97.       const int maxiter = 20;      // ought not be necessary, but just in case,
  98.                                    // max 300 bits of precision
  99.       int expt;
  100.       double mantissa = frexp(x, &expt);
  101.       long exponent = expt;
  102.       double intpart;
  103.       int k = 0;
  104.       while (mantissa != 0.0 && k++ < maxiter)
  105.       { mantissa *= width; // shift double mantissa
  106.         mantissa = modf(mantissa, &intpart);
  107.         num <<= shift;
  108.         num += (long)intpart;
  109.         exponent -= shift;
  110.       }
  111.       if (exponent > 0)
  112.         num <<= (unsigned)exponent;
  113.       else if (exponent < 0)
  114.         den <<= (unsigned)(-exponent);
  115.       if (neg)
  116.         num = -num;
  117.     }
  118.     normalize();
  119.   }
  120.  
  121.  
  122.  
  123.  
  124. // operators
  125.  
  126. rational& rational::operator+= (const rational& r)
  127.   if (den == r.den)
  128.     num += r.num;
  129.   else
  130.     { num = num*r.den + r.num*den;
  131.       den *= r.den;
  132.      }
  133.   return *this;
  134. }
  135.  
  136. rational& rational::operator-= (const rational& r)
  137. { if (den == r.den)
  138.     num -= r.num;
  139.   else
  140.     { num = num*r.den - r.num*den;
  141.       den *= r.den;
  142.      }
  143.   return *this;
  144. }
  145.  
  146. rational& rational::operator*= (const rational& r)
  147. { num *= r.num;
  148.   den *= r.den;
  149.   return *this;
  150. }
  151.  
  152. rational& rational::operator/= (const rational& r)
  153.   if (r.num.PTR->sign == 0) error_handler(1,"division by 0");
  154.  
  155.   if (r.num.PTR->sign == -1)
  156.     { num *= -r.den;
  157.       den *= -r.num;
  158.      }
  159.    else
  160.     { num *= r.den;
  161.       den *= r.num;
  162.      }
  163.   return *this;
  164. }
  165.  
  166.  
  167. rational& rational::operator= (const rational& r)
  168. { if (this == &r) return *this;
  169.   num = r.num;
  170.   den = r.den;
  171.   return *this;
  172. }
  173.  
  174.  
  175.  
  176. void rational::invert()
  177.   if (num.PTR->sign == 0) error_handler(1,"Zero denominator!");
  178.  
  179.   integer tmp = num;
  180.   if (num.PTR->sign == 1)
  181.     { num = den;
  182.       den = tmp;
  183.      }
  184.   else
  185.     { num = -den;
  186.       den = -tmp;
  187.      }
  188. }
  189.  
  190.  
  191. rational rational::inverse()
  192.   if (num.PTR->sign == 0) error_handler(1,"Zero denominator!");
  193.   
  194.   if (num.PTR->sign == 1)
  195.      return rational(den,num);
  196.   else
  197.      return rational(-den,-num);
  198. }
  199.  
  200.  
  201.  
  202.  
  203. int rational::cmp(const rational& x, const rational& y)
  204. { int xsign = sign(x.num);
  205.   int ysign = sign(y.num);
  206.  
  207.   if (xsign == 0) return -ysign;
  208.   if (ysign == 0) return  xsign;
  209.  
  210.   if (xsign == ysign) 
  211.     return compare(x.num * y.den, y.num * x.den);
  212.   else 
  213.     return compare(xsign,ysign);
  214. }
  215.  
  216.  
  217. // friend functions
  218.  
  219. rational pow(const rational& r, int i)
  220.   //r.normalize();
  221.  
  222.   rational mul(r);
  223.   rational result(1,1);
  224.  
  225.   if (i < 0) 
  226.   { mul = mul.inverse();
  227.     i = -i;
  228.    }
  229.  
  230.   while (i--)
  231.   { result.num *= mul.num;
  232.     result.den *= mul.den;
  233.    }
  234.  
  235.   return result;
  236.  }
  237.  
  238.  
  239. rational pow(const rational& r, integer I)
  240.   //r.normalize();
  241.  
  242.   rational mul(r);
  243.   rational result(1,1);
  244.  
  245.   if (I < 0)
  246.   { mul = mul.inverse();
  247.     I=-I;
  248.    }
  249.  
  250.   while (I-- != 0)
  251.   { result.num *= mul.num;
  252.     result.den *= mul.den;
  253.    }
  254.  
  255.   return result;
  256.  }
  257.  
  258.  
  259. double rational::to_double() const
  260.   if (num == 0) return 0;
  261.   
  262.   integer p = 1;
  263.  
  264.   if (den > abs(num)) p = den/num;
  265.   
  266.   integer q = ((num*p) << 53)/den;
  267.   
  268.   return (q.to_double()/p.to_double()) * ldexp(1.0,-53);
  269.  } 
  270.  
  271.  
  272. /*
  273.  double rational::to_double() const
  274.  { return div(bigfloat(num),bigfloat(den),53).to_double();
  275.  }
  276. */
  277.  
  278.  
  279.  
  280. // floor, ceil, round (use schooldiv!)
  281.  
  282. integer floor(const rational& r)
  283. { integer x = r.num/r.den;
  284.   if (sign(r.num) == -1 && r.num%r.den != 0) x--;
  285.   return x;
  286.  }
  287.  
  288.  
  289. integer ceil(const rational& r)
  290. { integer x = r.num/r.den; 
  291.   if (sign(r.num) == -1 && r.num%r.den != 0) x++;
  292.   return x;
  293.  }
  294.  
  295.  
  296. integer round(const rational& r)
  297. { integer rem;
  298.   integer quot = (r.num).div(r.den, rem);
  299.  
  300.   rem <<= 1;
  301.   if (sign(rem) < 0) 
  302.       { if (-rem >= r.den) quot--; }
  303.   else 
  304.       { if ( rem >= r.den) quot++; } 
  305.  
  306.   return quot;
  307. }
  308.  
  309.  
  310.  
  311. ostream& operator<< (ostream& s, const rational& r)
  312. {  s << r.num << "/" << r.den; 
  313.    return s; 
  314. }
  315.  
  316. istream& operator>> (istream& in, rational& r)
  317.    // Format: "r.num / r.den"
  318.  
  319.    char c;
  320.  
  321.    do in.get(c); while (isspace(c));
  322.    in.putback(c);
  323.  
  324.    integer rx;
  325.    in >> rx;
  326.  
  327.    do in.get(c); while (isspace(c));
  328.    if (c != '/') { error_handler(1,"/ expected"); }
  329.  
  330.    do in.get(c); while (isspace(c));
  331.    in.putback(c);
  332.  
  333.    integer ry;
  334.    in >> ry;
  335.  
  336.    r = rational(rx,ry);
  337.  
  338.    return in;
  339. }
  340.  
  341.  
  342.  
  343.  
  344.   rational& rational::operator++ ()       { num += den; return *this; }
  345.   rational& rational::operator-- ()       { num -= den; return *this; }
  346.   integer   rational::numerator()   const { return num; }
  347.   integer   rational::denominator() const { return den; }
  348.   void      rational::negate()            { num = - num; }
  349.  
  350.  
  351.   rational operator+(const rational& x, const rational& y)
  352.   { rational z = x; return z += y; }
  353.  
  354.   rational operator-(const rational& x, const rational& y)
  355.   { rational z = x; return z -= y; }
  356.  
  357.   rational operator*(const rational& x, const rational& y)
  358.   { rational z = x; return z *= y; }
  359.  
  360.   rational operator/(const rational& x, const rational& y)
  361.   { rational z = x; return z /= y; }
  362.  
  363.   rational operator-(const rational& x)
  364.   { return rational(-x.num,x.den); }
  365.  
  366.   int sign(const rational& r)
  367.   { return sign(r.num); }
  368.  
  369.   rational abs(const rational& r)
  370.   { if (sign(r.num) > -1) return r; else return -r; }
  371.  
  372.   rational sqr(const rational& r)
  373.   { return rational(r.num*r.num, r.den*r.den); }
  374.  
  375.   integer trunc(const rational& r)
  376.   { return (r.num / r.den); }
  377.  
  378.  
  379.  
  380. // comparison operators
  381.  
  382.   bool operator==(const rational& x, const rational& y)
  383.   { return x.num * y.den == x.den * y.num; }
  384.  
  385.   bool operator==(const rational& x, int y)
  386.   { return x.den * y == x.num; }
  387.  
  388.   bool operator==(int x, const rational& y)
  389.   { return y.den * x == y.num; }
  390.  
  391.   bool operator==(const rational& x, const integer& y)
  392.   { return x.den * y == x.num; }
  393.  
  394.   bool operator==(const integer& x, const rational& y)
  395.   { return y.den * x == y.num; }
  396.  
  397.   bool operator!=(const rational& x, const rational& y)
  398.   { return x.num * y.den != x.den * y.num; }
  399.  
  400.   bool operator!=(const rational& x, int y)
  401.   { return x.den * y != x.num; }
  402.  
  403.   bool operator!=(int x, const rational& y)
  404.   { return y.den * x != y.num; }
  405.  
  406.   bool operator!=(const rational& x, const integer& y)
  407.   { return x.den * y != x.num; }
  408.  
  409.   bool operator!=(const integer& x, const rational& y)
  410.   { return y.den * x != y.num; }
  411.     
  412.   bool operator<(const rational& x, const rational& y)
  413.   { return rational::cmp(x,y) < 0; }
  414.  
  415.   bool operator<=(const rational& x, const rational& y)
  416.   { return rational::cmp(x,y) <= 0; }
  417.  
  418.   bool operator>(const rational& x, const rational& y)
  419.   { return rational::cmp(x,y) > 0; }
  420.  
  421.   bool operator>=(const rational& x, const rational& y)
  422.   { return rational::cmp(x,y) >= 0; }
  423.  
  424.  
  425.  
  426. rational small_rational_between(const rational& X, const rational& Y)
  427. {  
  428.   // This procedure is similar to Figures 6, 7 in the paper by 
  429.   // Canny et al:
  430.   // "A Rational Rotation Method for Robust Geometric Algorithms"
  431.   // (Proc. of the 8th ACM Symposium on Computational Geometry, 
  432.   //  pages 251-260, 1992)
  433.  
  434.   if (Y < X) 
  435.     error_handler(1,
  436.       "small_rational_between: precondition violated");
  437.  
  438.   integer floor_y = floor(Y);
  439.   if (floor_y >= X) return floor_y;
  440.  
  441.   integer p0 = 0, q0 = 1, p1 = 1, q1 = 1, r;
  442.   rational x = X-floor_y, y = Y-floor_y;
  443.   rational z, result;
  444.  
  445.   while(1)
  446.   {  
  447.    // we have the invariant (I):
  448.    //         0 <= p0/q0 < x <= y < p1/q1 <= 1
  449.       
  450.       r = floor( (p1-q1*x)/(q0*x-p0) );
  451.       p1 = r*p0+p1; q1 = r*q0+q1;
  452.       z = rational(p1,q1);
  453.       if (z <= y) 
  454.       {
  455.         result = rational(p1+q1*floor_y,q1); 
  456.         break;
  457.       }
  458.  
  459.    // Invariant (I) from above holds again 
  460.  
  461.       r = floor( (q0*y-p0)/(p1-q1*y) );
  462.       p0 = p0+r*p1; q0 = q0+r*q1;
  463.       z = rational(p0,q0);
  464.       if (z >= x) 
  465.       { 
  466.         result = rational(p0+q0*floor_y,q0);
  467.         break;
  468.       }
  469.   } 
  470.   
  471.   if ((result > Y) || (result < X))
  472.          error_handler(1,
  473.            "small_rational_between: result wrong");
  474.   return result;
  475. }   
  476.  
  477.  
  478.  
  479. rational small_rational_near(const rational& X, rational epsilon)
  480. {  
  481.   // returns a small rational between X-epsilon and X+epsilon
  482.   // precondition: epsilon >= 0
  483.  
  484.   if (sign(epsilon) < 0)
  485.      error_handler(1,
  486.         "small_rational_near: precondition violated");
  487.  
  488.   return small_rational_between(X-epsilon,X+epsilon);
  489. }
  490.  
  491.