home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / bbs / gnu / libg++-2.6-fsf.lha / libg++-2.6 / libg++ / src / Fix.cc < prev    next >
C/C++ Source or Header  |  1994-06-28  |  13KB  |  664 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3. Copyright (C) 1989 Free Software Foundation
  4.     written by Doug Lea (dl@rocky.oswego.edu)
  5.  
  6. This file is part of the GNU C++ Library.  This library is free
  7. software; you can redistribute it and/or modify it under the terms of
  8. the GNU Library General Public License as published by the Free
  9. Software Foundation; either version 2 of the License, or (at your
  10. option) any later version.  This library is distributed in the hope
  11. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  12. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13. PURPOSE.  See the GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. //
  19. // Fix.cc : variable length fixed point data type class functions
  20. //
  21.  
  22. #ifdef __GNUG__
  23. #pragma implementation
  24. #endif
  25. #include <Fix.h>
  26. #include <std.h>
  27. #include <Obstack.h>
  28. #include <AllocRing.h>
  29. #include <strstream.h>
  30.  
  31. // member constants
  32.  
  33. const _G_uint16_t Fix::min_length;
  34. const _G_uint16_t Fix::max_length;
  35. const double Fix::min_value;
  36. const double Fix::max_value;
  37.  
  38. // default parameters
  39.  
  40. _G_uint16_t Fix::default_length = 16;
  41. int    Fix::default_print_width = 8;
  42.  
  43. Fix::PEH Fix::overflow_handler = Fix::overflow_saturate;
  44.  
  45. Fix::Rep Fix::Rep_0    = { 16, 1, 1, { 0 } };
  46. Fix::Rep Fix::Rep_m1    = { 16, 1, 1, { 0x8000 } };
  47. Fix::Rep Fix::Rep_quotient_bump = { 16, 1, 1, { 0x4000 } };
  48.  
  49. // error handling
  50.  
  51. void
  52. Fix::default_error_handler(const char* msg)
  53. {
  54.   cerr << "Fix: " << msg << "\n";
  55.   abort();
  56. }
  57.  
  58. void
  59. Fix::default_range_error_handler(const char* msg)
  60. {
  61.   cerr << "Fix: range error in " << msg << "\n";
  62.   //abort();
  63. }
  64.  
  65. one_arg_error_handler_t 
  66.   Fix::error_handler = Fix::default_error_handler,
  67.   Fix::range_error_handler = Fix::default_range_error_handler;
  68.  
  69. one_arg_error_handler_t
  70. Fix::set_error_handler(one_arg_error_handler_t f)
  71. {
  72.   one_arg_error_handler_t old = error_handler;
  73.   error_handler = f;
  74.   return old;
  75. }
  76.  
  77. one_arg_error_handler_t
  78. Fix::set_range_error_handler(one_arg_error_handler_t f)
  79. {
  80.   one_arg_error_handler_t old = range_error_handler;
  81.   range_error_handler = f;
  82.   return old;
  83. }
  84.  
  85. void
  86. Fix::error(const char* msg)
  87. {
  88.   error_handler(msg);
  89. }
  90.  
  91. void
  92. Fix::range_error(const char* msg)
  93. {
  94.   range_error_handler(msg);
  95. }
  96.  
  97. // Fix::Rep allocation and initialization functions
  98.  
  99. static inline Fix::Rep*
  100. _new_Fix(_G_uint16_t len)
  101. {
  102.   int siz = (((_G_uint32_t) len + 15) >> 4);
  103.   if (siz <= 0) siz = 1;
  104.   unsigned int allocsiz = (sizeof(Fix::Rep) + (siz - 1) * sizeof(_G_uint16_t));
  105.   Fix::Rep* z = (Fix::Rep*)(new char[allocsiz]);
  106.   memset(z, 0, allocsiz);
  107.   z->len = len;
  108.   z->siz = siz;
  109.   z->ref = 1;
  110.   return z;
  111. }
  112.  
  113. Fix::Rep*
  114. Fix::new_Fix(_G_uint16_t len)
  115. {
  116.   return _new_Fix(len);
  117. }
  118.  
  119. Fix::Rep*
  120. Fix::new_Fix(_G_uint16_t len, const Rep* x)
  121. {
  122.   Rep* z = _new_Fix(len);
  123.   return copy(x,z);
  124. }
  125.  
  126. Fix::Rep*
  127. Fix::new_Fix(_G_uint16_t len, double d)
  128. {
  129.   Rep* z = _new_Fix(len);
  130.  
  131.   if ( d == max_value )
  132.   {
  133.     z->s[0] = 0x7fff;
  134.     for ( int i=1; i < z->siz; i++ )
  135.       z->s[i] = 0xffff;
  136.   }
  137.   else if ( d < min_value || d > max_value )
  138.     range_error("declaration");
  139.   else
  140.   {
  141.     if (d < 0)
  142.       d += 2.0;
  143.     d *= 32768;
  144.     for ( int i=0; i < z->siz; i++ )
  145.     {
  146.       z->s[i] = (_G_uint16_t )d;
  147.       d -= z->s[i];
  148.       d *= 65536;
  149.     }
  150.     if ( d >= 32768 )
  151.       z->s[z->siz-1]++;
  152.   }
  153.   mask(z);
  154.   return z;
  155. }
  156.  
  157. // convert to a double 
  158.  
  159. double
  160. value(const Fix& x)
  161.   double d = 0.0;
  162.   for ( int i=x.rep->siz-1; i >= 0; i-- )
  163.   {
  164.     d += x.rep->s[i];
  165.     d *= 1./65536.;
  166.   }
  167.   d *= 2.;
  168.   return d < 1. ? d : d - 2.;
  169. }
  170.  
  171. // extract mantissa to Integer
  172.  
  173. Integer
  174. mantissa(const Fix& x)
  175. {
  176.   Integer a = 1, b=1;
  177.   for ( int i=0; i < x.rep->siz; i++ )
  178.   {
  179.     a <<= 16;
  180.     a += x.rep->s[i];
  181.     b <<= 16;
  182.   }
  183.   return a-b;
  184. }
  185.  
  186. // comparison functions
  187.   
  188. inline static int
  189. docmp(const _G_uint16_t* x, const _G_uint16_t* y, int siz)
  190. {
  191.   int diff = (_G_int16_t )*x - (_G_int16_t )*y;
  192.   while ( --siz && !diff )
  193.     diff = (_G_int32_t )(_G_uint32_t )*++x - (_G_int32_t )(_G_uint32_t )*++y;
  194.   return diff;
  195. }
  196.  
  197. inline static int
  198. docmpz(const _G_uint16_t* x, int siz)
  199. {
  200.   while ( siz-- )
  201.     if ( *x++ ) return 1;
  202.   return 0;
  203. }
  204.  
  205. int
  206. Fix::compare(const Rep* x, const Rep* y)
  207. {
  208.   if ( x->siz == y->siz )
  209.     return docmp(x->s, y->s, x->siz);
  210.   else
  211.   {
  212.     int r;
  213.     const Rep* longer, *shorter;
  214.     if ( x->siz > y->siz )
  215.     {
  216.       longer = x;
  217.       shorter = y;
  218.       r = 1;
  219.     }
  220.     else
  221.     {
  222.       longer = y;
  223.       shorter = x;
  224.       r = -1;
  225.     }
  226.     int diff = docmp(x->s, y->s, shorter->siz);
  227.     if ( diff )
  228.       return diff;
  229.     else if ( docmpz(&longer->s[shorter->siz], longer->siz-shorter->siz) )
  230.       return r;
  231.     else
  232.       return 0;
  233.   }
  234. }
  235.  
  236. // arithmetic functions
  237.  
  238. Fix::Rep*
  239. Fix::add(const Rep* x, const Rep* y, Rep* r)
  240. {
  241.   _G_uint16_t xsign = x->s[0], ysign = y->s[0];
  242.   const Rep* longer, *shorter;
  243.   if ( x->len >= y->len )
  244.     longer = x, shorter = y;
  245.   else
  246.     longer = y, shorter = x;
  247.   if ( r == NULL )
  248.     r = new_Fix(longer->len);
  249.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  250.     r->s[i] = 0;
  251.   for ( ; i >= shorter->siz; i-- )
  252.     r->s[i] = longer->s[i];
  253.   _G_uint32_t sum = 0, carry = 0;
  254.   for ( ; i >= 0; i-- )
  255.   {
  256.     sum = carry + (_G_uint32_t )x->s[i] + (_G_uint32_t )y->s[i];
  257.     carry = sum >> 16;
  258.     r->s[i] = sum;
  259.   }
  260.   if ( (xsign ^ sum) & (ysign ^ sum) & 0x8000 )
  261.     overflow_handler(r);
  262.   return r;
  263. }
  264.  
  265. Fix::Rep*
  266. Fix::subtract(const Rep* x, const Rep* y, Rep* r)
  267. {
  268.   _G_uint16_t xsign = x->s[0], ysign = y->s[0];
  269.   const Rep* longer, *shorter;
  270.   if ( x->len >= y->len )
  271.     longer = x, shorter = y;
  272.   else
  273.     longer = y, shorter = x;
  274.   if ( r == NULL )
  275.     r = new_Fix(longer->len);
  276.   for ( int i=r->siz-1; i >= longer->siz; i-- )
  277.     r->s[i] = 0;
  278.   for ( ; i >= shorter->siz; i-- )
  279.     r->s[i] = (longer == x ? x->s[i] : -y->s[i]);
  280.   _G_int16_t carry = 0;
  281.   _G_uint32_t sum = 0;
  282.   for ( ; i >= 0; i-- )
  283.   {
  284.     sum = (_G_int32_t )carry + (_G_uint32_t )x->s[i] - (_G_uint32_t )y->s[i];
  285.     carry = sum >> 16;
  286.     r->s[i] = sum;
  287.   }
  288.   if ( (xsign ^ sum) & (~ysign ^ sum) & 0x8000 )
  289.     overflow_handler(r);
  290.   return r;
  291. }
  292.  
  293. Fix::Rep*
  294. Fix::multiply(const Rep* x, const Rep* y, Rep* r)
  295. {
  296.   if ( r == NULL )
  297.     r = new_Fix(x->len + y->len);
  298.   int xsign = x->s[0] & 0x8000,
  299.     ysign = y->s[0] & 0x8000;
  300.   Fix X(x->len), Y(y->len);
  301.   if ( xsign )
  302.     x = negate(x,X.rep);
  303.   if ( ysign )
  304.     y = negate(y,Y.rep);
  305.   for ( int i=0; i < r->siz; i++ )
  306.     r->s[i] = 0;
  307.   for ( i=x->siz-1; i >= 0; i-- )
  308.   {
  309.     _G_uint32_t carry = 0;
  310.     for ( int j=y->siz-1; j >= 0; j-- ) 
  311.     {
  312.       int k = i + j + 1;
  313.       _G_uint32_t a = (_G_uint32_t )x->s[i] * (_G_uint32_t )y->s[j];
  314.       _G_uint32_t b = ((a << 1) & 0xffff) + carry;
  315.       if ( k < r->siz )
  316.       {
  317.     b += r->s[k];
  318.         r->s[k] = b;
  319.       }
  320.       if ( k < (int)r->siz + 1 )
  321.         carry = (a >> 15) + (b >> 16);
  322.     }
  323.     r->s[i] = carry;
  324.   }
  325.   if ( xsign != ysign )
  326.     negate(r,r);
  327.   return r;
  328. }
  329.  
  330. Fix::Rep*
  331. Fix::multiply(const Rep* x, int y, Rep* r)
  332. {
  333.   if ( y != (_G_int16_t )y )
  334.     range_error("multiply by int -- int too large");
  335.   if ( r == NULL )
  336.     r = new_Fix(x->len);
  337.   for ( int i=r->siz-1; i >= x->siz; i-- )
  338.     r->s[i] = 0;
  339.   _G_int32_t a, carry = 0;
  340.   for ( ; i > 0; i-- )
  341.   {
  342.     a = (_G_int32_t) (_G_uint32_t )x->s[i] * y + carry;
  343.     r->s[i] = a;
  344.     carry = a >> 16;        // assumes arithmetic right shift
  345.   }
  346.   a = (_G_int32_t) (_G_int16_t )x->s[0] * y + carry;
  347.   r->s[0] = a;
  348.   a &= 0xffff8000L;
  349.   if ( a != 0xffff8000L && a != 0L ) {
  350.     r->s[0] = 0x8000 ^ x->s[0] ^ y;
  351.     overflow_handler(r);
  352.   }
  353.   return r;
  354. }
  355.  
  356. Fix::Rep*
  357. Fix::divide(const Rep* x, const Rep* y, Rep* q, Rep* r)
  358. {
  359.   int xsign = x->s[0] & 0x8000, 
  360.     ysign = y->s[0] & 0x8000;
  361.   if ( q == NULL )
  362.     q = new_Fix(x->len);
  363.   copy(&Rep_0,q);
  364.   if ( r == NULL )
  365.     r = new_Fix(x->len + y->len - 1);
  366.   if ( xsign )
  367.     negate(x,r);
  368.   else
  369.     copy(x,r);
  370.   Fix Y(y->len);
  371.   Rep* y2 = ( ysign ? negate(y,Y.rep) : copy(y,Y.rep) );
  372.   if ( !compare(y2) )
  373.     range_error("division -- division by zero");
  374.   else if ( compare(x,y2) >= 0 )
  375.