home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 7 / FreshFishVol7.bin / bbs / gnu / libg++-2.6-fsf.lha / libg++-2.6 / libg++ / src / Fix16.cc < prev    next >
C/C++ Source or Header  |  1993-06-01  |  6KB  |  239 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /* 
  3. Copyright (C) 1988 Free Software Foundation
  4.     written by Kurt Baudendistel (gt-eedsp!baud@gatech.edu)
  5.     adapted for libg++ by Doug Lea (dl@rocky.oswego.edu)
  6.  
  7. This file is part of the GNU C++ Library.  This library is free
  8. software; you can redistribute it and/or modify it under the terms of
  9. the GNU Library General Public License as published by the Free
  10. Software Foundation; either version 2 of the License, or (at your
  11. option) any later version.  This library is distributed in the hope
  12. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  13. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  14. PURPOSE.  See the GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. //
  21. // Fix.cc : fixed precision class support functions
  22. //
  23.  
  24. #ifdef __GNUG__
  25. #pragma implementation
  26. #endif
  27. #include <Fix16.h>
  28.  
  29. // basic operators too large to be inline
  30.  
  31. short Fix16::assign(double d) 
  32.   if (d == 1.0)
  33.     return Fix16_m_max;
  34.   else if (d > Fix16_max)
  35.   {
  36.     short i = Fix16_m_max;
  37.     range_error(i);
  38.     return i;
  39.   }
  40.   else if (d < Fix16_min)
  41.   {
  42.     short i = Fix16_m_min;
  43.     range_error(i);
  44.     return i;
  45.   }
  46.   else 
  47.     return round(Fix16_mult * d);
  48. }
  49.  
  50. long Fix32::assign(double d) 
  51.   if (d == 1.0)
  52.     return Fix32_m_max;
  53.   else if (d > Fix32_max)
  54.   {
  55.     long i = Fix32_m_max;
  56.     range_error(i);
  57.     return i;
  58.   }
  59.   else if (d < Fix32_min)
  60.   {
  61.     long i = Fix32_m_min;
  62.     range_error(i);
  63.     return i;
  64.   }
  65.   else 
  66.     return round(Fix32_mult * d);
  67. }
  68.  
  69.  
  70. Fix32 operator * (const Fix32& a, const Fix32& b)
  71. {
  72. // break a and b into lo and hi parts, and do a multiple-precision
  73. // multiply, with rounding
  74.  
  75.   int apos = (a.m >= 0);
  76.   unsigned long ua = (apos)? a.m : - a.m;
  77.   ua <<= 1; // ua is biased so result will be 31 bit mantissa, not 30:
  78.   unsigned long hi_a = (ua >> 16) & ((1 << 16) - 1);
  79.   unsigned long lo_a = ua & ((1 << 16) - 1);
  80.  
  81.   int bpos = (b.m >= 0);
  82.   unsigned long ub = (bpos)? b.m : -b.m;
  83.   unsigned long hi_b = (ub >> 16) & ((1 << 16) - 1);
  84.   unsigned long lo_b = ub & ((1 << 16) - 1);
  85.  
  86.   unsigned long r = lo_a * lo_b + (1 << 15);
  87.   r = (r >> 16) + hi_a * lo_b + lo_a * hi_b + (1 << 15);
  88.   r = (r >> 16) + hi_a * hi_b;
  89.   long p = (apos != bpos)? -r : r;
  90.   return Fix32(p);
  91. }
  92.  
  93. Fix16 operator / (const Fix16& a, const Fix16& b)
  94. {
  95.   short q;
  96.   int apos = (a.m >= 0);
  97.   long la = (apos)? a.m : -a.m;
  98.   long scaled_a = la << 15;
  99.   int bpos = (b.m >= 0);
  100.   short sb = (bpos)? b.m: -b.m;
  101.   if (la >= sb)
  102.   {
  103.     q = (apos == bpos)? Fix16_m_max: Fix16_m_min;
  104.     a.range_error(q);
  105.   }
  106.   else
  107.   {
  108.     q = scaled_a / sb;
  109.     if ((scaled_a % sb) >= (sb / 2)) ++q;
  110.     if (apos != bpos) q = -q;
  111.   }
  112.   return Fix16(q);
  113. }
  114.  
  115. Fix32 operator / (const Fix32& a, const Fix32& b)
  116. {
  117.   long q;
  118.   int apos = (a.m >= 0);
  119.   unsigned long la = (apos)? a.m : -a.m;
  120.   int bpos = (b.m >= 0);
  121.   unsigned long lb = (bpos)? b.m: -b.m;
  122.   if (la >= lb)
  123.   {
  124.     q = (apos == bpos)? Fix32_m_max: Fix32_m_min;
  125.     a.range_error(q);
  126.   }
  127.   else                        // standard shift-based division alg
  128.   {
  129.     q = 0;
  130.     long r = la;
  131.  
  132.     for (int i = 32; i > 0; i--)
  133.     {
  134.     if ((unsigned)(r) > lb) {
  135.         q = (q << 1) | 1;
  136.         r -= lb;
  137.     }
  138.     else
  139.         q = (q << 1);
  140.     r <<= 1;
  141.     }
  142.  
  143.     if (apos != bpos) q = -q;    // Fix sign
  144.   }    
  145.   return Fix32(q);
  146. }
  147.  
  148.  
  149. // error handling
  150.  
  151. void Fix16::overflow(short& i) const
  152. {
  153.   (*Fix16_overflow_handler)(i);
  154. }
  155.  
  156. void Fix32::overflow(long& i) const
  157. {
  158.   (*Fix32_overflow_handler)(i);
  159. }
  160.  
  161. void Fix16::range_error(short& i) const
  162. {
  163.   (*Fix16_range_error_handler)(i);
  164. }
  165.  
  166. void Fix32::range_error(long& i) const
  167. {
  168.   (*Fix32_range_error_handler)(i);
  169. }
  170.  
  171. // data definitions
  172.  
  173. Fix16_peh Fix16_overflow_handler = Fix16_overflow_saturate;
  174. Fix32_peh Fix32_overflow_handler = Fix32_overflow_saturate;
  175.  
  176. Fix16_peh Fix16_range_error_handler = Fix16_warning;
  177. Fix32_peh Fix32_range_error_handler = Fix32_warning;
  178.  
  179. //function definitions
  180.  
  181. Fix16_peh set_Fix16_overflow_handler(Fix16_peh new_handler) {
  182.   Fix16_peh old_handler = Fix16_overflow_handler;
  183.   Fix16_overflow_handler = new_handler;
  184.   return old_handler;
  185. }
  186.  
  187. Fix32_peh set_Fix32_overflow_handler(Fix32_peh new_handler) {
  188.   Fix32_peh old_handler = Fix32_overflow_handler;
  189.   Fix32_overflow_handler = new_handler;
  190.   return old_handler;
  191. }
  192.  
  193. void set_overflow_handler(Fix16_peh handler16, Fix32_peh handler32) {
  194.   set_Fix16_overflow_handler(handler16);
  195.   set_Fix32_overflow_handler(handler32);
  196. }
  197.  
  198. Fix16_peh set_Fix16_range_error_handler(Fix16_peh new_handler) {
  199.   Fix16_peh old_handler = Fix16_range_error_handler;
  200.   Fix16_range_error_handler = new_handler;
  201.   return old_handler;
  202. }
  203.  
  204. Fix32_peh set_Fix32_range_error_handler(Fix32_peh new_handler) {
  205.   Fix32_peh old_handler = Fix32_range_error_handler;
  206.   Fix32_range_error_handler = new_handler;
  207.   return old_handler;
  208. }
  209.  
  210. void set_range_error_handler(Fix16_peh handler16, Fix32_peh handler32) {
  211.   set_Fix16_range_error_handler(handler16);
  212.   set_Fix32_range_error_handler(handler32);
  213. }
  214.  
  215. void Fix16_overflow_saturate(short& i)
  216.   { i = (i > 0 ? Fix16_m_min : Fix16_m_max); }
  217. void Fix16_ignore(short&) {}
  218. void Fix16_warning(short&)
  219.   { cerr << "warning: Fix16 result out of range\n"; }
  220. void Fix16_overflow_warning_saturate(short& i)
  221.   { cerr << "warning: Fix16 result out of range\n"; 
  222.    Fix16_overflow_saturate(i); }
  223. void Fix16_abort(short&)
  224.   { cerr << "error: Fix16 result out of range\n"; abort(); }
  225.  
  226. void Fix32_ignore(long&) {}
  227. void Fix32_overflow_saturate(long& i)
  228.   { i = (i > 0 ? Fix32_m_min : Fix32_m_max); }
  229. void Fix32_warning(long&)
  230.   { cerr << "warning: Fix32 result out of range\n"; }
  231. void Fix32_overflow_warning_saturate(long& i)
  232.   { cerr << "warning: Fix32 result out of range\n"; 
  233.    Fix32_overflow_saturate(i); }
  234. void Fix32_abort(long&)
  235.   { cerr << "error: Fix32 result out of range\n"; abort(); }
  236.  
  237.