_rational.c
上传用户:gzelex
上传日期:2007-01-07
资源大小:707k
文件大小:9k
开发平台:

MultiPlatform

  1. /*******************************************************************************
  2. +
  3. +  LEDA-R  3.2.3
  4. +
  5. +  _rational.c
  6. +
  7. +  Copyright (c) 1995  by  Max-Planck-Institut fuer Informatik
  8. +  Im Stadtwald, 66123 Saarbruecken, Germany     
  9. +  All rights reserved.
  10. *******************************************************************************/
  11. #include <LEDA/basic.h>
  12. #include <LEDA/rational.h>
  13. #include <math.h>
  14. #include <ctype.h>
  15. // hidden functions
  16. rational& rational::normalize()
  17. // divide numerator and denominator by their greatest common divisor
  18.   { // den is assumed to be nonzero and positive
  19.     if (num == den) 
  20.       { 
  21.         num = den = 1; 
  22. return (*this); 
  23.       }
  24.     if (-num == den) 
  25.       { 
  26.         num = -1; den = 1; 
  27. return (*this); 
  28.       }
  29.     integer ggt = gcd(num, den);
  30.     if (ggt != 1) 
  31.       {
  32.         num /= ggt;
  33.         den /= ggt;
  34.       };
  35.     return (*this);
  36.   }
  37. rational& rational::simplify(const integer& a)
  38. // divide numerator and denominator by number a
  39. {
  40.   integer r;
  41.   den = den.div(a,r);
  42.   if (r !=0)
  43.     error_handler(1,"rational::simplify: argument does not divide denominator");
  44.   num = num.div(a,r);
  45.   if (r !=0)
  46.     error_handler(1,"rational::simplify: argument does not divide numerator");
  47.   return *this;
  48. }
  49. // Constructors
  50. rational::rational(double x)
  51.   { num = 0; den = 1;
  52.     if (x != 0.0)
  53.     { int neg = (x < 0);
  54.       if (neg) x = -x;
  55.       const unsigned shift = 15;   // a safe shift per step
  56.       const double width = 32768;  // = 2^shift
  57.       const int maxiter = 20;      // ought not be necessary, but just in case,
  58.                                    // max 300 bits of precision
  59.       int expt;
  60.       double mantissa = frexp(x, &expt);
  61.       long exponent = expt;
  62.       double intpart;
  63.       int k = 0;
  64.       while (mantissa != 0.0 && k++ < maxiter) {
  65.         mantissa *= width; // shift double mantissa
  66.         mantissa = modf(mantissa, &intpart);
  67.         num <<= shift;
  68.         num += (long)intpart;
  69.         exponent -= shift;
  70.       }
  71.       if (exponent > 0)
  72.         num <<= (unsigned)exponent;
  73.       else if (exponent < 0)
  74.         den <<= (unsigned)(-exponent);
  75.       if (neg)
  76.         num = -num;
  77.     } // if (x != 0) then
  78.     (*this).normalize();
  79.   }
  80. rational::rational(int n, int d)
  81.   { if (d == 0) 
  82.       {
  83.         error_handler(1,"Zero denominator!");
  84.       }
  85.     else 
  86.       {
  87.         if (d < 0) 
  88.           {
  89.             num = -integer(n);   //wegen reference counting notwendig
  90.             den = -integer(d);
  91.           }
  92.         else
  93.           {
  94.             num = integer(n);
  95.             den = integer(d);
  96.           }
  97.       }
  98. //      (*this).normalize();
  99.   }
  100. rational::rational(const integer& n, const integer& d)
  101.   { if (d.PTR->sign == 0) 
  102.       {
  103.         error_handler(1,"Zero denominator!");
  104.       }
  105.     else 
  106.       {
  107.         if (d.PTR->sign == -1) 
  108.           {
  109.             num = -integer(n);
  110.             den = -integer(d);
  111.           }
  112.         else
  113.           {
  114.             num = integer(n);
  115.             den = integer(d);
  116.           }
  117.       }
  118. //      (*this).normalize();
  119.   }
  120. // Arithmetic Operators
  121. rational& rational::operator+= (const rational& r)
  122.   { num = num * r.den + r.num * den;
  123.     den *= r.den;
  124. //    return (*this).normalize();
  125.     return (*this);
  126.   }
  127. rational& rational::operator-= (const rational& r)
  128.   { num = num * r.den - r.num * den;
  129.     den *= r.den;
  130. //    return (*this).normalize();
  131.     return (*this);
  132.   }
  133. rational& rational::operator*= (const rational& r)
  134.   { num *= r.num;
  135.     den *= r.den;
  136. //    return (*this).normalize();
  137.     return (*this);
  138.   }
  139. rational& rational::operator/= (const rational& r)
  140.   { if (r.num.PTR->sign == 0) 
  141.       {
  142.         // r == 0
  143.         error_handler(1,"Division by 0!");
  144.       }
  145.     else 
  146.       {
  147.         // r.num != 0
  148. if (r.num.PTR->sign == -1)
  149.   {
  150.             num *= -r.den;
  151.             den *= -r.num;
  152.           }
  153.         else
  154.   {
  155.             num *= r.den;
  156.             den *= r.num;
  157.           }
  158.       }
  159. //    return (*this).normalize();
  160.     return (*this);
  161.   }
  162. // Assignment Operator
  163. rational& rational::operator= (const rational& r)
  164.   { if (this == &r) return *this; // to handle r = r correctly
  165.     num = r.num;
  166.     den = r.den;
  167.     return *this;
  168.   }
  169. // some useful member-functions
  170. void rational::invert()
  171.   { if (num.PTR->sign == 0) 
  172.       {
  173.         error_handler(1,"Zero denominator!");
  174.       }
  175.     else 
  176.       {
  177.         integer tmp = num;
  178. if (num.PTR->sign == 1)
  179.   {
  180.             num = den;
  181.             den = tmp;
  182.           }
  183.         else
  184.   {
  185.             num = -den;
  186.             den = -tmp;
  187.           }
  188.       }
  189.   }
  190. rational rational::inverse()
  191.   { if (num.PTR->sign == 0) 
  192.       {
  193.         error_handler(1,"Zero denominator!");
  194.         return (*this);
  195.       }
  196.     else
  197.       {
  198.         if (num.PTR->sign == 1)
  199.           { 
  200.             rational tmp(den,num);
  201.             return tmp;
  202.   }
  203.         else
  204.   {
  205.             rational tmp(-den,-num);
  206.             return tmp;
  207.           }
  208.       }
  209.   }
  210. // friend functions
  211. int rational::cmp(const rational& x, const rational& y)
  212.   { int xsign = sign(x.num);
  213.     int ysign = sign(y.num);
  214.     if (xsign == 0) return -ysign;
  215.     if (ysign == 0) return xsign;
  216.     // now (x != 0) && (y != 0)
  217.     int diff = xsign - ysign;
  218.     if (diff == 0) 
  219.     { integer leftop  = x.num * y.den;
  220.       integer rightop = y.num * x.den;
  221.       if (leftop < rightop) return -1;
  222.       else return (leftop > rightop);
  223.      }
  224.     else return diff;
  225.   }
  226. /*
  227. int rational::cmp(const rational& x, int y)
  228.     int  xsign = sign(x.num), ysign;
  229.     if (y == 0) ysign = 0;
  230.     else ysign = (y > 0) ? 1 : -1;
  231.     if (xsign == 0) 
  232.       return -ysign; 
  233.     if (ysign == 0) 
  234.       return xsign; 
  235.     // now (x != 0) && (y != 0)
  236.     return compare(x.num, y*x.den);
  237.     int diff = xsign - ysign;
  238.     if (diff == 0) 
  239.       {
  240.         if (x.num < y * x.den)  
  241.           return -1; 
  242.         else  
  243.   return (x.num > y * x.den); 
  244.       }
  245.     else return diff;
  246. }
  247. int rational::cmp(int x, const rational& y)
  248.   { 
  249.     int ysign = sign(y.num), xsign;
  250.     if (x == 0) xsign = 0;
  251.     else xsign = (x > 0) ? 1 : -1;
  252.     if (xsign == 0) 
  253.       return -ysign;
  254.     if (ysign == 0) 
  255.       return xsign;
  256.     // now (x != 0) && (y != 0)
  257.     return compare(x*y.den, y.num);
  258.     int diff = xsign - ysign;
  259.     if (diff == 0) {
  260.       integer  leftop = integer(x) * y.den, rightop = y.num;
  261.       if (leftop < rightop) { return -1; }
  262.       else { return (leftop > rightop); }
  263.     }
  264.     else return diff;
  265.     return 0;
  266.   }
  267. */
  268. // other useful friend functions
  269. rational pow(const rational& r, int l)
  270. // no need to normalize since num and den are relatively prime
  271.   { rational mul(r), result(1,1);
  272.     if (l < 0) {
  273.       mul = mul.inverse();
  274.       l = -l;
  275.     }
  276.     for (int i = 1; i <= l; i++) {
  277.       result.num *= mul.num;
  278.       result.den *= mul.den;
  279.     }
  280.     return result;
  281.   }
  282. rational pow(const rational& r, integer I)
  283. // no need to normalize since num and den are relatively prime
  284.   { rational mul(r), result(1,1);
  285.     if (sign(I) == -1) {
  286.       mul = mul.inverse();
  287.       I=-I;
  288.     }
  289.     for (integer i = 1; i < I; i++) {
  290.       result.num *= mul.num;
  291.       result.den *= mul.den;
  292.     }
  293.     return result;
  294.   }
  295. /*
  296. rational::operator double() const
  297.   { integer
  298.       numvar = num,
  299.       denvar = den;
  300.     if (numvar == integer(0)) { return 0; }
  301.     
  302.     const integer MDP = 1000000;    // my_double_precision
  303.     long s = 0;
  304.     integer quot = (numvar / denvar); // integer quotient
  305.     while (abs(quot) < MDP) {
  306.       numvar *= 10;
  307.       s++;
  308.       quot = (numvar / denvar);
  309.     }
  310.     // |quot| > MDP
  311.     // num_new == 10^s * num_old
  312.     while (abs(quot) > MDP) {
  313.       quot /= 10;
  314.       s--;
  315.     }
  316.     // MDP/10 < |quot| < MDP
  317.     // num_old/den_old == quot * 10^{-s}
  318.     double result = (double)longasI(quot);
  319.     // transform integer into double via long
  320.     if (s >= 0) {
  321.       for (int i = 0; i < s; i++) { result /= 10; };
  322.     }
  323.     else {
  324.       for (int i = 0; i > s; i--) { result *= 10; };
  325.     }
  326.     return result;
  327.   }; 
  328. */
  329. // floor, ceil und round besser durch schooldiv
  330. integer floor(const rational& r)
  331.   { integer x;
  332.     x = r.num/r.den;
  333.     if ((sign(r.num) == -1) && (r.num%r.den != 0)) x--;
  334.     return x;
  335.   }
  336. integer ceil(const rational& r)
  337.   { integer x;
  338.     x = r.num/r.den; 
  339.     if ((sign(r.num) == -1) && (r.num%r.den != 0)) x++;
  340.     return x;
  341.   };
  342. /* Noch ausgeklammert
  343. integer round(const rational& r)
  344.   { integer rem, quot;
  345.     Idiv(quot, rem, r.num, r.den);
  346.     rem <<= 1;
  347.     if (rem >= r.den) {
  348.       if (sign(r.num) >= 0) { quot++; }
  349.       else { quot--; }
  350.     }
  351.     return quot;
  352.   }
  353. */
  354. istream& operator>> (istream& in, rational& r)
  355.   { // Format: "r.num / r.den"
  356.     integer rx, ry;
  357.     char c;
  358.     do in.get(c); while (isspace(c));
  359.     in.putback(c);
  360.     in >> rx;
  361.    
  362.     do in.get(c); while (isspace(c));
  363.     if (c != '/') { error_handler(1,"/ expected"); }
  364.     do in.get(c); while (isspace(c));
  365.     in.putback(c);
  366.    
  367.     in >> ry;
  368.     r = rational(rx,ry);
  369.     // to guarantee the value is normalized, denominator is nonzero ...
  370.     return in;
  371.   }