⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fix.cc

📁 早期freebsd实现
💻 CC
字号:
// This may look like C code, but it is really -*- C++ -*-/*Copyright (C) 1989 Free Software Foundation    written by Doug Lea (dl@rocky.oswego.edu)This file is part of the GNU C++ Library.  This library is freesoftware; you can redistribute it and/or modify it under the terms ofthe GNU Library General Public License as published by the FreeSoftware Foundation; either version 2 of the License, or (at youroption) any later version.  This library is distributed in the hopethat it will be useful, but WITHOUT ANY WARRANTY; without even theimplied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULARPURPOSE.  See the GNU Library General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA.*///// Fix.cc : variable length fixed point data type class functions//#ifdef __GNUG__#pragma implementation#endif#include <Fix.h>#include <std.h>#include <Obstack.h>#include <AllocRing.h>#include <strstream.h>// default parametersuint16 Fix_default_length = 16;int    Fix_default_print_width = 8;Fix_peh Fix_overflow_handler = Fix_overflow_saturate;_Frep _Frep_0	= { 16, 1, 1, { 0 } };_Frep _Frep_m1	= { 16, 1, 1, { 0x8000 } };_Frep _Frep_quotient_bump = { 16, 1, 1, { 0x4000 } };// error handlingvoid default_Fix_error_handler(const char* msg){  cerr << "Fix: " << msg << "\n";  abort();}void default_Fix_range_error_handler(const char* msg){  cerr << "Fix: range error in " << msg << "\n";  //abort();}one_arg_error_handler_t   Fix_error_handler = default_Fix_error_handler,  Fix_range_error_handler = default_Fix_range_error_handler;one_arg_error_handler_t set_Fix_error_handler(one_arg_error_handler_t f){  one_arg_error_handler_t old = Fix_error_handler;  Fix_error_handler = f;  return old;}one_arg_error_handler_t set_Fix_range_error_handler(one_arg_error_handler_t f){  one_arg_error_handler_t old = Fix_range_error_handler;  Fix_range_error_handler = f;  return old;}void Fix::error(const char* msg){  (*Fix_error_handler)(msg);}void Fix::range_error(const char* msg){  (*Fix_range_error_handler)(msg);}// _Frep allocation and initialization functionsstatic inline _Fix _new_Fix(uint16 len){  int siz = (((uint32 )len + 15) >> 4);  if (siz <= 0) siz = 1;  unsigned int allocsiz = (sizeof(_Frep) + (siz - 1) * sizeof(uint16));  _Fix z = (_Fix)(new char[allocsiz]);  memset(z, 0, allocsiz);  z->len = len;  z->siz = siz;  z->ref = 1;  return z;}_Fix new_Fix(uint16 len){  return _new_Fix(len);}_Fix new_Fix(uint16 len, _Fix x){  _Fix z = _new_Fix(len);  return copy(x,z);}_Fix new_Fix(uint16 len, double d){  _Fix z = _new_Fix(len);  if ( d == _Fix_max_value )  {    z->s[0] = 0x7fff;    for ( int i=1; i < z->siz; i++ )      z->s[i] = 0xffff;  }  else if ( d < _Fix_min_value || d > _Fix_max_value )    (*Fix_range_error_handler)("declaration");  else  {    if (d < 0)      d += 2.0;    d *= 32768;    for ( int i=0; i < z->siz; i++ )    {      z->s[i] = (uint16 )d;      d -= z->s[i];      d *= 65536;    }    if ( d >= 32768 )      z->s[z->siz-1]++;  }  mask(z);  return z;}// convert to a double double value(Fix& x){   double d = 0.0;  for ( int i=x.rep->siz-1; i >= 0; i-- )  {    d += x.rep->s[i];    d *= 1./65536.;  }  d *= 2.;  return d < 1. ? d : d - 2.;}// extract mantissa to IntegerInteger mantissa(Fix& x){  Integer a = 1, b=1;  for ( int i=0; i < x.rep->siz; i++ )  {    a = (a << 16) + x.rep->s[i];    b <<= 16;  }  return a-b;}// comparison functions  inline static int docmp(uint16* x, uint16* y, int siz){  int diff = (int16 )*x - (int16 )*y;  while ( --siz && !diff )    diff = (int32 )(uint32 )*++x - (int32 )(uint32 )*++y;  return diff;}inline static int docmpz(uint16* x, int siz){  while ( siz-- )    if ( *x++ ) return 1;  return 0;}int compare(_Fix x, _Fix y){  if ( x->siz == y->siz )    return docmp(x->s, y->s, x->siz);  else  {    int r;    _Fix longer, shorter;    if ( x->siz > y->siz )    {      longer = x;      shorter = y;      r = 1;    }    else    {      longer = y;      shorter = x;      r = -1;    }    int diff = docmp(x->s, y->s, shorter->siz);    if ( diff )      return diff;    else if ( docmpz(&longer->s[shorter->siz], longer->siz-shorter->siz) )      return r;    else      return 0;  }}// arithmetic functions_Fix add(_Fix x, _Fix y, _Fix r){  uint16 xsign = x->s[0], ysign = y->s[0];  _Fix longer, shorter;  if ( x->len >= y->len )    longer = x, shorter = y;  else    longer = y, shorter = x;  if ( r == NULL )    r = new_Fix(longer->len);  for ( int i=r->siz-1; i >= longer->siz; i-- )    r->s[i] = 0;  for ( ; i >= shorter->siz; i-- )    r->s[i] = longer->s[i];  uint32 sum = 0, carry = 0;  for ( ; i >= 0; i-- )  {    sum = carry + (uint32 )x->s[i] + (uint32 )y->s[i];    carry = sum >> 16;    r->s[i] = sum;  }  if ( (xsign ^ sum) & (ysign ^ sum) & 0x8000 )    (*Fix_overflow_handler)(r);  return r;}_Fix subtract(_Fix x, _Fix y, _Fix r){  uint16 xsign = x->s[0], ysign = y->s[0];  _Fix longer, shorter;  if ( x->len >= y->len )    longer = x, shorter = y;  else    longer = y, shorter = x;  if ( r == NULL )    r = new_Fix(longer->len);  for ( int i=r->siz-1; i >= longer->siz; i-- )    r->s[i] = 0;  for ( ; i >= shorter->siz; i-- )    r->s[i] = (longer == x ? x->s[i] : -y->s[i]);  int16 carry = 0;  uint32 sum = 0;  for ( ; i >= 0; i-- )  {    sum = (int32 )carry + (uint32 )x->s[i] - (uint32 )y->s[i];    carry = sum >> 16;    r->s[i] = sum;  }  if ( (xsign ^ sum) & (~ysign ^ sum) & 0x8000 )    (*Fix_overflow_handler)(r);  return r;}_Fix multiply(_Fix x, _Fix y, _Fix r){  if ( r == NULL )    r = new_Fix(x->len + y->len);  int xsign = x->s[0] & 0x8000,    ysign = y->s[0] & 0x8000;  Fix X(x->len), Y(y->len);  if ( xsign )    x = negate(x,X.rep);  if ( ysign )    y = negate(y,Y.rep);  for ( int i=0; i < r->siz; i++ )    r->s[i] = 0;  for ( i=x->siz-1; i >= 0; i-- )  {    uint32 carry = 0;    for ( int j=y->siz-1; j >= 0; j-- )     {      int k = i + j + 1;      uint32 a = (uint32 )x->s[i] * (uint32 )y->s[j];      uint32 b = ((a << 1) & 0xffff) + carry;      if ( k < r->siz )      {	b += r->s[k];        r->s[k] = b;      }      if ( k < r->siz + 1 )        carry = (a >> 15) + (b >> 16);    }    r->s[i] = carry;  }  if ( xsign != ysign )    negate(r,r);  return r;}_Fix multiply(_Fix x, int y, _Fix r){  if ( y != (int16 )y )    (*Fix_range_error_handler)("multiply by int -- int too large");  if ( r == NULL )    r = new_Fix(x->len);  for ( int i=r->siz-1; i >= x->siz; i-- )    r->s[i] = 0;  int32 a, carry = 0;  for ( ; i > 0; i-- )  {    a = (int32 )(uint32 )x->s[i] * y + carry;    r->s[i] = a;    carry = a >> 16;		// assumes arithmetic right shift  }  a = (int32 )(int16 )x->s[0] * y + carry;  r->s[0] = a;  a &= 0xffff8000L;  if ( a != 0xffff8000L && a != 0L ) {    r->s[0] = 0x8000 ^ x->s[0] ^ y;    (*Fix_overflow_handler)(r);  }  return r;}_Fix divide(_Fix x, _Fix y, _Fix q, _Fix r){  int xsign = x->s[0] & 0x8000,     ysign = y->s[0] & 0x8000;  if ( q == NULL )    q = new_Fix(x->len);  copy(&_Frep_0,q);  if ( r == NULL )    r = new_Fix(x->len + y->len - 1);  if ( xsign )    negate(x,r);  else    copy(x,r);  Fix Y(y->len);  y = ( ysign ? negate(y,Y.rep) : copy(y,Y.rep) );  if ( !compare(y) )    (*Fix_range_error_handler)("division -- division by zero");  else if ( compare(x,y) >= 0 )    if ( compare(x,y) == 0 && (xsign ^ ysign) != 0 )    {      copy(&_Frep_m1,q);      copy(&_Frep_0,r);    }    else      (*Fix_range_error_handler)("division");  else  {    _Fix t;    Fix S(r->len),      W(q->len,&_Frep_quotient_bump);    for ( int i=1; i < q->len; i++ )    {      shift(y,-1,y);      subtract(r,y,S.rep);      int s_status = compare(S.rep);      if ( s_status == 0 )       {	t = r, r = S.rep, S.rep = t;	break;      }      else if ( s_status > 0 )      {	t = r, r = S.rep, S.rep = t;	add(q,W.rep,q);      }      shift(W.rep,-1,W.rep);    }    if ( xsign ^ ysign )      negate(q,q);  }  return q;}_Fix shift(_Fix x, int y, _Fix r){  if ( y == 0 )    return x;  else if ( r == NULL )    r = new_Fix(x->len);  int ay = abs((long) y),    ayh = ay >> 4,    ayl = ay & 0x0f;  int xl, u, ilow, ihigh;  uint16 *rs, *xsl, *xsr;  if ( y > 0 )  {    rs = r->s;    xsl = x->s + ayh;    xsr = xsl + 1;    xl = ayl;    u = 1;    ihigh = x->siz - ayh - 1;    ilow = 0;  }  else  {    rs = &r->s[r->siz - 1];    xsr = &x->s[r->siz - 1] - ayh;    xsl = xsr - 1;    xl = 16 - ayl;    u = -1;    ihigh = r->siz - ayh - 1;    ilow = ihigh - x->siz;  }  int xr = 16 - xl;  uint16 xrmask = 0xffffL >> xr;  for ( int i=0; i < ilow; i++, rs+=u, xsl+=u, xsr+=u )    *rs = 0;  for ( ; i < ihigh; i++, rs+=u, xsl+=u, xsr+=u )    *rs = (*xsl << xl) + ((*xsr >> xr) & xrmask);  *rs = (y > 0 ? (*xsl << xl) : ((*xsr >> xr) & xrmask));  rs += u;  for ( ; ++i < r->siz; rs+=u )    *rs = 0;  return r;}_Fix negate(_Fix x, _Fix r){  if ( r == NULL )    r = new_Fix(x->len);  uint32 carry = 1;  for ( int i=r->siz-1; i >= x->siz; i-- )    r->s[i] = 0;  for ( ; i >= 0; i-- )  {    uint32 a = (uint16 )~x->s[i] + carry;	// bug work-around    r->s[i] = a;    carry = a >> 16;  }  return r;}// io functionsFix atoF(const char* a, int len){  return Fix(len,atof(a));}extern AllocRing _libgxx_fmtq;void Fix::printon(ostream& s, int width){  char format[20];  double val = value(*this);  int old_precision = s.precision(width-3);  ios::fmtflags old_flags = s.setf(ios::fixed, ios::fixed|ios::scientific);  if (val >= 0)      s << ' ';  s.width(width-2);  s << val;  s.precision(old_precision);  s.flags(old_flags);}char* Ftoa(Fix& x, int width){  int wrksiz = width + 2;  char *fmtbase = (char *) _libgxx_fmtq.alloc(wrksiz);  ostrstream stream(fmtbase, wrksiz);    x.printon(stream, width);  stream << ends;  return fmtbase;}extern Obstack _libgxx_io_ob;Fix Fix::operator %= (int y){  Fix r((int )rep->len + y, *this); return *this = r;}istream& operator >> (istream& s, Fix& y){  int got_one = 0;#ifdef _OLD_STREAMS  if (!s.good())  {    return s;  }#else  if (!s.ipfx(0))  {    s.set(ios::failbit); // Redundant if using GNU iostreams.    return s;  }#endif  char sign = 0, point = 0;  char ch;  s >> ws;  if (!s.good())  {    s.set(_fail);    return s;  }  while (s.get(ch))  {    if (ch == '-')    {      if (sign == 0)      {        sign = 1;        _libgxx_io_ob.grow(ch);      }      else        break;    }    if (ch == '.')    {      if (point == 0)      {        point = 1;        _libgxx_io_ob.grow(ch);      }      else        break;    }    else if (ch >= '0' && ch <= '9')    {      got_one = 1;      _libgxx_io_ob.grow(ch);    }    else      break;  }  char * p = (char*)(_libgxx_io_ob.finish(0));  if (s.good())    s.putback(ch);  if (!got_one)    s.set(_fail);  else    y = atoF(p);  _libgxx_io_ob.free(p);  return s;}void show(Fix& x){  cout << "len = " << x.rep->len << "\n";  cout << "siz = " << x.rep->siz << "\n";  cout << "ref = " << x.rep->ref << "\n";  cout << "man = ";#ifdef _OLD_STREAMS  cout << Itoa(mantissa(x),16,4*x.rep->siz);#else  int old_flags = cout.setf(ios::hex, ios::hex|ios::dec|ios::oct);  cout.width(4*x.rep->siz);  cout << mantissa(x);  cout.setf(old_flags, ios::hex|ios::dec|ios::oct);#endif  cout << "\n";  cout << "val = " << value(x) << "\n";}// parameter setting operationsFix_peh set_overflow_handler(Fix_peh new_handler) {  Fix_peh old_handler = Fix_overflow_handler;  Fix_overflow_handler = new_handler;  return old_handler;}int Fix_set_default_length(int newlen){  uint16 oldlen = Fix_default_length;  if ( newlen < _Fix_min_length || newlen > _Fix_max_length )    (*Fix_error_handler)("illegal length in Fix_set_default_length");  Fix_default_length = newlen;  return oldlen;}// overflow handlersvoid Fix_overflow_saturate(_Fix& r) {  if ( (int16 )r->s[0] > 0 )   {    r->s[0] = 0x8000;    for ( int i=1; i < r->siz; i++ )      r->s[i] = 0;  }  else  {    r->s[0] = 0x7fff;    for ( int i=1; i < r->siz; i++ )      r->s[i] = 0xffff;    mask(r);  }}void Fix_overflow_wrap(_Fix& r) {}void Fix_overflow_warning_saturate(_Fix& r) {  Fix_overflow_warning(r);  Fix_overflow_saturate(r);}void Fix_overflow_warning(_Fix& r) {  cerr << "Fix: overflow warning\n"; }void Fix_overflow_error(_Fix& r) {  cerr << "Fix: overflow error\n";   abort();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -