home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / gnu / g__lib / fix.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-23  |  10.8 KB  |  558 lines

  1. //
  2. // Fix.cc : variable length fixed point data type class functions
  3. //
  4.  
  5. #include <Fix.h>
  6. #include <Obstack.h>
  7. #include <std.h>
  8.  
  9. // default parameters
  10.  
  11. uint16 Fix_default_length = 16;
  12. int    Fix_default_print_width = 8;
  13.  
  14. Fix_peh Fix_overflow_handler = Fix_overflow_saturate;
  15.  
  16. _Frep _Frep_0    = { 16, 1, 1, { 0 } };
  17. _Frep _Frep_m1    = { 16, 1, 1, { 0x8000 } };
  18. _Frep _Frep_quotient_bump = { 16, 1, 1, { 0x4000 } };
  19.  
  20. // error handling
  21.  
  22. void default_Fix_error_handler(char* msg)
  23. {
  24.   cerr << "Fix: " << msg << "\n";
  25.   abort();
  26. }
  27.  
  28. void default_Fix_range_error_handler(char* msg)
  29. {
  30.   cerr << "Fix: range error in " << msg << "\n";
  31.   //abort();
  32. }
  33.  
  34. one_arg_error_handler_t 
  35.   Fix_error_handler = default_Fix_error_handler,
  36.   Fix_range_error_handler = default_Fix_range_error_handler;
  37.  
  38. one_arg_error_handler_t set_Fix_error_handler(one_arg_error_handler_t f)
  39. {
  40.   one_arg_error_handler_t old = Fix_error_handler;
  41.   Fix_error_handler = f;
  42.   return old;
  43. }
  44.  
  45. one_arg_error_handler_t set_Fix_range_error_handler(one_arg_error_handler_t f)
  46. {
  47.   one_arg_error_handler_t old = Fix_range_error_handler;
  48.   Fix_range_error_handler = f;
  49.   return old;
  50. }
  51.  
  52. void Fix::error(char* msg)
  53. {
  54.   (*Fix_error_handler)(msg);
  55. }
  56.  
  57. void Fix::range_error(char* msg)
  58. {
  59.   (*Fix_range_error_handler)(msg);
  60. }
  61.  
  62. // _Frep allocation and initialization functions
  63.  
  64. inline _Fix _new_Fix(uint16 len)
  65. {
  66.   int siz = ((uint32 )len + 15) >> 4;
  67.  
  68.   _Fix z = malloc(sizeof(_Frep) + (siz - 1) * sizeof(uint16));
  69.   if (z == 0)
  70.     (*Fix_error_handler)("out of memory");
  71.  
  72.   z->len = len;
  73.   z->siz = siz;
  74.   z->ref = 1;
  75.   return z;
  76. }
  77.  
  78. _Fix new_Fix(uint16 len)
  79. {
  80.   return _new_Fix(len);
  81. }
  82.  
  83. _Fix new_Fix(uint16 len, _Fix x)
  84. {
  85.   _Fix z = _new_Fix(len);
  86.   return copy(x,z);
  87. }
  88.  
  89. _Fix new_Fix(uint16 len, double d)
  90. {
  91.   _Fix z = _new_Fix(len);
  92.  
  93.   if ( d == _Fix_max_value )
  94.   {
  95.     z->s[0] = 0x7fff;
  96.     for ( int i=1; i < z->siz; i++ )
  97.       z->s[i] = 0xffff;
  98.   }
  99.   else if ( d < _Fix_min_value || d > _Fix_max_value )
  100.     (*Fix_range_error_handler)("declaration");
  101.   else
  102.   {
  103.     d *= 32768;
  104.     for ( int i=0; i < z->siz; i++ )
  105.     {
  106.       z->s[i] = (uint16 )d;
  107.       d -= z->s[i];
  108.       d *= 65536;
  109.     }
  110.     if ( d >= 32768 )
  111.       z->s[z->siz-1]++;
  112.   }
  113.   mask(z);
  114.   return z;
  115. }
  116.  
  117. // convert to a double 
  118.  
  119. double value(Fix& x)
  120.   double d = 0.0;
  121.   for ( int i=x.rep->siz-1; i >= 0; i-- )
  122.   {
  123.     d += x.rep->s[i];
  124.     d *= 1./65536.;
  125.   }
  126.   d *= 2.;
  127.   return d < 1. ? d : d - 2.;
  128. }
  129.  
  130. // extract mantissa to Integer
  131.  
  132. Integer mantissa(Fix& x)
  133. {
  134.   Integer a = 1, b=1;
  135.   for ( int i=0; i < x.rep->siz; i++ )
  136.     a = (a << 16) + x.rep->s[i], b <<= 16;
  137.   return a-b;
  138. }
  139.  
  140. // comparison functions
  141.   
  142. inline static int docmp(uint16* x, uint16* y, int siz)
  143. {
  144.   int diff = (int16 )*x - (int16 )*y;
  145.   while ( --siz && !diff )
  146.     diff = (int32 )(uint32 )*++x - (int32 )(uint32 )*++y;
  147.   return diff;
  148. }
  149.  
  150. inline static int docmpz(uint16* x, int siz)
  151. {
  152.   while ( siz-- )
  153.     if ( *x++ ) return 1;
  154.   return 0;
  155. }
  156.  
  157. int compare(_Fix x, _Fix y = &_Frep_0)
  158. {
  159.   if ( x->siz == y->siz )
  160.     return docmp(x->s, y->s, x->siz);
  161.   else
  162.   {
  163.     int r;
  164.     _Fix longer, shorter;
  165.     if ( x->siz > y->siz )
  166.     {
  167.       longer = x;
  168.       shorter = y;
  169.       r = 1;
  170.     }
  171.     else
  172.     {
  173.       longer = y;
  174.       shorter = x;
  175.       r = -1;
  176.     }
  177.     int diff = docmp(x->s, y->s, shorter->siz);
  178.     if ( diff )
  179.       return diff;
  180.     else if ( docmpz(&longer->s[shorter->siz], longer->siz-shorter->siz) )
  181.       return r;
  182.     else
  183.       return 0;
  184.   }
  185. }
  186.  
  187. // arithmetic functions
  188.  
  189. _Fix add(_Fix x, _Fix y, _Fix r = NULL)
  190. {
  191.   uint16 xsign = x->s[0], ysign = y->s[0];
  192.   _Fix longer, shorter;
  193.   if ( x->len >= y->len )
  194.     longer = x, shorter = y;
  195.   else
  196.     longer = y, shorter = x;
  197.   if ( r == NULL )
  198.     r = new_Fix(longer->len);
  199.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  200.     r->s[i] = 0;
  201.   for ( ; i >= shorter->siz; i-- )
  202.     r->s[i] = longer->s[i];
  203.   uint32 sum, carry = 0;
  204.   for ( ; i >= 0; i-- )
  205.   {
  206.     sum = carry + (uint32 )x->s[i] + (uint32 )y->s[i];
  207.     carry = sum >> 16;
  208.     r->s[i] = sum;
  209.   }
  210.   if ( (xsign ^ sum) & (ysign ^ sum) & 0x8000 )
  211.     (*Fix_overflow_handler)(r);
  212.   return r;
  213. }
  214.  
  215. _Fix subtract(_Fix x, _Fix y, _Fix r = NULL)
  216. {
  217.   uint16 xsign = x->s[0], ysign = y->s[0];
  218.   _Fix longer, shorter;
  219.   if ( x->len >= y->len )
  220.     longer = x, shorter = y;
  221.   else
  222.     longer = y, shorter = x;
  223.   if ( r == NULL )
  224.     r = new_Fix(longer->len);
  225.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  226.     r->s[i] = 0;
  227.   for ( ; i >= shorter->siz; i-- )
  228.     r->s[i] = (longer == x ? x->s[i] : -y->s[i]);
  229.   int16 carry = 0;
  230.   uint32 sum;
  231.   for ( ; i >= 0; i-- )
  232.   {
  233.     sum = (int32 )carry + (uint32 )x->s[i] - (uint32 )y->s[i];
  234.     carry = sum >> 16;
  235.     r->s[i] = sum;
  236.   }
  237.   if ( (xsign ^ sum) & (~ysign ^ sum) & 0x8000 )
  238.     (*Fix_overflow_handler)(r);
  239.   return r;
  240. }
  241.  
  242. _Fix multiply(_Fix x, _Fix y, _Fix r = NULL)
  243. {
  244.   if ( r == NULL )
  245.     r = new_Fix(x->len + y->len - 1);
  246.   int xsign = x->s[0] & 0x8000,
  247.     ysign = y->s[0] & 0x8000;
  248.   Fix X(x->len), Y(y->len);
  249.   if ( xsign )
  250.     x = negate(x,X.rep);
  251.   if ( ysign )
  252.     y = negate(y,Y.rep);
  253.   for ( int i=0; i < r->siz; i++ )
  254.     r->s[i] = 0;
  255.   for ( i=x->siz-1; i >= 0; i-- )
  256.   {
  257.     uint32 carry = 0;
  258.     for ( int j=y->siz-1; j >= 0; j-- ) 
  259.     {
  260.       int k = i + j + 1;
  261.       uint32 a = (uint32 )x->s[i] * (uint32 )y->s[j];
  262.       uint32 b = ((a << 1) & 0xffff) + carry;
  263.       if ( k < r->siz )
  264.       {
  265.     b += r->s[k];
  266.         r->s[k] = b;
  267.       }
  268.       if ( k < r->siz + 1 )
  269.         carry = (a >> 15) + (b >> 16);
  270.     }
  271.     r->s[i] = carry;
  272.   }
  273.   if ( xsign != ysign )
  274.     negate(r,r);
  275.   return r;
  276. }
  277.  
  278. _Fix multiply(_Fix x, int y, _Fix r = NULL )
  279. {
  280.   if ( y != (int16 )y )
  281.     (*Fix_range_error_handler)("multiply by int -- int too large");
  282.   if ( r == NULL )
  283.     r = new_Fix(x->len);
  284.   for ( int i=r->siz-1; i >= x->siz; i-- )
  285.     r->s[i] = 0;
  286.   int32 a, carry = 0;
  287.   for ( ; i > 0; i-- )
  288.   {
  289.     a = (int32 )(uint32 )x->s[i] * y + carry;
  290.     r->s[i] = a;
  291.     carry = a >> 16;        // assumes arithmetic right shift
  292.   }
  293.   a = (int32 )(int16 )x->s[0] * y + carry;
  294.   r->s[0] = a;
  295.   a &= 0xffff8000L;
  296.   if ( a != 0xffff8000L && a != 0L ) {
  297.     r->s[0] = 0x8000 ^ x->s[0] ^ y;
  298.     (*Fix_overflow_handler)(r);
  299.   }
  300.   return r;
  301. }
  302.  
  303. _Fix divide(_Fix x, _Fix y, _Fix q = NULL, _Fix r = NULL)
  304. {
  305.   int xsign = x->s[0] & 0x8000, 
  306.     ysign = y->s[0] & 0x8000;
  307.   if ( q == NULL )
  308.     q = new_Fix(x->len);
  309.   copy(&_Frep_0,q);
  310.   if ( r == NULL )
  311.     r = new_Fix(x->len + y->len - 1);
  312.   if ( xsign )
  313.     negate(x,r);
  314.   else
  315.     copy(x,r);
  316.   Fix Y(y->len);
  317.   y = ( ysign ? negate(y,Y.rep) : copy(y,Y.rep) );
  318.   if ( !compare(y) )
  319.     (*Fix_range_error_handler)("division -- division by zero");
  320.   else if ( compare(x,y) >= 0 )
  321.     if ( compare(x,y) == 0 && xsign ^ ysign != 0 )
  322.     {
  323.       copy(&_Frep_m1,q);
  324.       copy(&_Frep_0,r);
  325.     }
  326.     else
  327.       (*Fix_range_error_handler)("division");
  328.   else
  329.   {
  330.     _Fix t;
  331.     Fix S(r->len),
  332.       W(q->len,&_Frep_quotient_bump);
  333.     for ( int i=1; i < q->len; i++ )
  334.     {
  335.       shift(y,-1,y);
  336.       subtract(r,y,S.rep);
  337.       int s_status = compare(S.rep);
  338.       if ( s_status == 0 ) 
  339.       {
  340.     t = r, r = S.rep, S.rep = t;
  341.     break;
  342.       }
  343.       else if ( s_status > 0 )
  344.       {
  345.     t = r, r = S.rep, S.rep = t;
  346.     add(q,W.rep,q);
  347.       }
  348.       shift(W.rep,-1,W.rep);
  349.     }
  350.     if ( xsign ^ ysign )
  351.       negate(q,q);
  352.   }
  353.   return q;
  354. }
  355.  
  356. _Fix shift(_Fix x, int y, _Fix r = NULL )
  357. {
  358.   if ( y == 0 )
  359.     return x;
  360.   else if ( r == NULL )
  361.     r = new_Fix(x->len);
  362.  
  363.   int ay = abs(y),
  364.     ayh = ay >> 4,
  365.     ayl = ay & 0x0f;
  366.   int xl, u, ilow, ihigh;
  367.   uint16 *rs, *xsl, *xsr;
  368.  
  369.   if ( y > 0 )
  370.   {
  371.     rs = r->s;
  372.     xsl = x->s + ayh;
  373.     xsr = xsl + 1;
  374.     xl = ayl;
  375.     u = 1;
  376.     ihigh = x->siz - ayh - 1;
  377.     ilow = 0;
  378.   }
  379.   else
  380.   {
  381.     rs = &r->s[r->siz - 1];
  382.     xsr = &x->s[r->siz - 1] - ayh;
  383.     xsl = xsr - 1;
  384.     xl = 16 - ayl;
  385.     u = -1;
  386.     ihigh = r->siz - ayh - 1;
  387.     ilow = ihigh - x->siz;
  388.   }
  389.  
  390.   int xr = 16 - xl;
  391.   uint16 xrmask = 0xffffL >> xr;
  392.   for ( int i=0; i < ilow; i++, rs+=u, xsl+=u, xsr+=u )
  393.     *rs = 0;
  394.   for ( ; i < ihigh; i++, rs+=u, xsl+=u, xsr+=u )
  395.     *rs = (*xsl << xl) + ((*xsr >> xr) & xrmask);
  396.   *rs = (y > 0 ? (*xsl << xl) : ((*xsr >> xr) & xrmask));
  397.   rs += u;
  398.   for ( ; i < r->siz; i++, rs+=u )
  399.     *rs = 0;
  400.   return r;
  401. }
  402.  
  403. _Fix negate(_Fix x, _Fix r = NULL)
  404. {
  405.   if ( r == NULL )
  406.     r = new_Fix(x->len);
  407.   uint32 carry = 1;
  408.   for ( int i=r->siz-1; i >= x->siz; i-- )
  409.     r->s[i] = 0;
  410.   for ( ; i >= 0; i-- )
  411.   {
  412.     uint32 a = (uint16 )~x->s[i] + carry;    // bug work-around
  413.     r->s[i] = a;
  414.     carry = a >> 16;
  415.   }
  416.   return r;
  417. }
  418.  
  419. // io functions
  420.  
  421. Fix atoF(const char* a, int len = Fix_default_length)
  422. {
  423.   return Fix(len,atof(a));
  424. }
  425.  
  426. char* Ftoa(Fix& x, int width = Fix_default_print_width)
  427. {
  428.   char *s = new char[width+1];
  429.   sprintf(s,"% *.*lf",width-2,width-3,value(x));
  430.   return s;
  431. }
  432.  
  433. extern Obstack _libgxx_io_ob;
  434. extern char* _libgxx_io_oblast;
  435.  
  436. Fix Fix::operator %= (int y)
  437. {
  438.   Fix r((int )rep->len + y, *this); return *this = r;
  439. }
  440.  
  441. istream& operator >> (istream& s, Fix& y)
  442. {
  443.   int got_one = 0;
  444.   if (!s.readable())
  445.   {
  446.     s.error();
  447.     return s;
  448.   }
  449.  
  450.   if (_libgxx_io_oblast) _libgxx_io_ob.free(_libgxx_io_oblast);
  451.  
  452.   char sign = 0, point = 0;
  453.   char ch;
  454.   s >> WS;
  455.   while (s.good())
  456.   {
  457.     s.get(ch);
  458.     if (ch == '-')
  459.     {
  460.       if (sign == 0)
  461.       {
  462.         sign = 1;
  463.         _libgxx_io_ob.grow(ch);
  464.       }
  465.       else
  466.         break;
  467.     }
  468.     if (ch == '.')
  469.     {
  470.       if (point == 0)
  471.       {
  472.         point = 1;
  473.         _libgxx_io_ob.grow(ch);
  474.       }
  475.       else
  476.         break;
  477.     }
  478.     else if (ch >= '0' && ch <= '9')
  479.     {
  480.       got_one = 1;
  481.       _libgxx_io_ob.grow(ch);
  482.     }
  483.     else
  484.       break;
  485.   }
  486.   char * p = (char*)(_libgxx_io_ob.finish(0));
  487.   _libgxx_io_oblast = p;
  488.   if (s.good())
  489.     s.unget(ch);
  490.   if (!got_one)
  491.     s.error();
  492.   else
  493.     y = atoF(p);
  494.   return s;
  495. }
  496.  
  497. void show(Fix& x)
  498. {
  499.   cout << "len = " << x.rep->len << "\n";
  500.   cout << "siz = " << x.rep->siz << "\n";
  501.   cout << "ref = " << x.rep->ref << "\n";
  502.   cout << "man = " << Itoa(mantissa(x),16,4*x.rep->siz) << "\n";
  503.   cout << "val = " << value(x) << "\n";
  504. }
  505.  
  506. // parameter setting operations
  507.  
  508. Fix_peh set_overflow_handler(Fix_peh new_handler) {
  509.   Fix_peh old_handler = Fix_overflow_handler;
  510.   Fix_overflow_handler = new_handler;
  511.   return old_handler;
  512. }
  513.  
  514. int Fix_set_default_length(int newlen)
  515. {
  516.   uint16 oldlen = Fix_default_length;
  517.   if ( newlen < _Fix_min_length || newlen > _Fix_max_length )
  518.     (*Fix_error_handler)("illegal length in Fix_set_default_length");
  519.   Fix_default_length = newlen;
  520.   return oldlen;
  521. }
  522.  
  523. // overflow handlers
  524.  
  525. void Fix_overflow_saturate(_Fix& r) {
  526.   if ( (int16 )r->s[0] > 0 ) 
  527.   {
  528.     r->s[0] = 0x8000;
  529.     for ( int i=1; i < r->siz; i++ )
  530.       r->s[i] = 0;
  531.   }
  532.   else
  533.   {
  534.     r->s[0] = 0x7fff;
  535.     for ( int i=1; i < r->siz; i++ )
  536.       r->s[i] = 0xffff;
  537.     mask(r);
  538.   }
  539. }
  540.  
  541. void Fix_overflow_wrap(_Fix& r) {}
  542.  
  543. void Fix_overflow_warning_saturate(_Fix& r) {
  544.   Fix_overflow_warning(r);
  545.   Fix_overflow_saturate(r);
  546. }
  547.  
  548. void Fix_overflow_warning(_Fix& r) {
  549.   cerr << "Fix: overflow warning\n"; 
  550. }
  551.  
  552. void Fix_overflow_error(_Fix& r) {
  553.   cerr << "Fix: overflow error\n"; 
  554.   abort();
  555. }
  556.  
  557.