rmath.h

Go to the documentation of this file.
00001 #ifndef __math_h__
00002 #define __math_h__
00003 
00004 #include <string>
00005 #include <float.h>
00006 
00007 #include "asserts.h"
00008 #include "types.h"
00009 #include "estring.h"
00010 
00011 /** A small set of numeric limits routines, since gcc prior to 3.x doesn't
00012  * have numeric_limits */
00013 
00014 // ---------------------------------------------------------------------------
00015 
00016 /** Find the maximum limit for a type, equivalent to
00017  * std::numeric_limits<T>.max() for systems that don't have the limits c++
00018  * header file. */
00019 template<typename T>
00020 static const T max_limit()
00021 {
00022         T tmp = 0;
00023         static T max = 0;
00024         static bool found = false;
00025 
00026         if (found) {
00027                 return(max);
00028         }
00029         
00030         tmp = 1;
00031         max = 0;
00032         while (tmp > max) {
00033                 max = tmp;
00034                 try {
00035                         tmp = (tmp * T(2)) + T(1);
00036                 }
00037                 catch(...) { }
00038         }
00039         found = true;
00040         return(max);
00041 }
00042 
00043 /** Find the maximum limit for a type, equivalent to
00044  * std::numeric_limits<T>.min() for systems that don't have the limits c++
00045  * header file.
00046  */
00047 template<typename T>
00048 static const T min_limit()
00049 {
00050         T tmp = 0;
00051         static T min = 0;
00052         static bool found = false;
00053 
00054         if (found) {
00055                 return(min);
00056         }
00057         
00058         tmp = -1;
00059         min = 0;
00060         while (tmp < min) {
00061                 min = tmp;
00062                 try {
00063                         tmp = (tmp * T(2)) - T(1);
00064                 }
00065                 catch(...) { }
00066         }
00067         
00068         try {
00069                 tmp = - max_limit<T>() - T(1);
00070         }
00071         catch(...) { }
00072         if (tmp < min) {
00073                 min = tmp;
00074         }
00075 
00076         found = true;
00077         return(min);
00078 }
00079 
00080 /** Return the largest possible number that a float may hold. */
00081 template<>
00082 static const float max_limit<float>()
00083 {
00084         return(FLT_MAX);
00085 }
00086 
00087 /** Return the smallest positive number that a float may hold.
00088  *
00089  * Caveat: This is in contrast to other types, where min_limit<T>() will return
00090  * either 0 or the largest possible negative number that the type may hold.  If
00091  * you are looking for the largest possible negative number for any given type,
00092  * use lowest_value<T>() instead.
00093  */
00094 template<>
00095 static const float min_limit<float>()
00096 {
00097         return(FLT_MIN);
00098 }
00099 
00100 /** Return the largest possible number that a double may hold. */
00101 template<>
00102 static const double max_limit<double>()
00103 {
00104         return(DBL_MAX);
00105 }
00106 
00107 /** Return the smallest positive number that a double may hold.
00108  *
00109  * Caveat: This is in contrast to other types, where min_limit<T>() will return
00110  * either 0 or the largest possible negative number that the type may hold.  If
00111  * you are looking for the largest possible negative number for any given type,
00112  * use lowest_value<T>() instead.
00113  */
00114 template<>
00115 static const double min_limit<double>()
00116 {
00117         return(DBL_MIN);
00118 }
00119 
00120 // ---------------------------------------------------------------------------
00121 
00122 /** Return the max_limit of a variable.
00123  *
00124  * This is handy to have because it means
00125  * that the author may change the type of a variable without having to track
00126  * down all uses of max_limit or min_limit to change the type they measure.
00127  */
00128 template<typename T>
00129 static const T max_limit(const T& a_arg)
00130 {
00131         T value;
00132 
00133         value = max_limit<T>();
00134 
00135         return(value);
00136 }
00137 
00138 /** Return the min_limit of a variable.
00139  *
00140  * This is handy to have because it means
00141  * that the author may change the type of a variable without having to track
00142  * down all uses of max_limit or min_limit to change the type they measure.
00143  */
00144 template<typename T>
00145 static const T min_limit(const T& a_arg)
00146 {
00147         T value;
00148 
00149         value = min_limit<T>();
00150 
00151         return(value);
00152 }
00153 
00154 // ---------------------------------------------------------------------------
00155 
00156 /** Return the maximum possible value a type may hold.
00157  *
00158  * This is just a convenience function to match lowest_value<T>().  All it does
00159  * is return the value of max_limit<T>().
00160  */
00161 template<typename T>
00162 static const T highest_value(void)
00163 {
00164         T value;
00165 
00166         value = max_limit<T>();
00167 
00168         return(value);
00169 }
00170 
00171 /** Return the maximum possible value of a variable. */
00172 template<typename T>
00173 static const T highest_value(const T& a_arg)
00174 {
00175         T value;
00176 
00177         value = highest_value<T>();
00178 
00179         return(value);
00180 }
00181 
00182 /** Return 0 for unsigned types, or the maximum negative value that the type
00183  * may hold.
00184  */
00185 template<typename T>
00186 static const T lowest_value(void)
00187 {
00188         T value;
00189 
00190         value = -max_limit<T>();
00191         if (value > min_limit<T>())
00192                 value = min_limit<T>();
00193         
00194         return(value);
00195 }
00196 
00197 /** Return 0 for unsigned types, or the maximum negative value that a variable
00198  * may hold.
00199  */
00200 template<typename T>
00201 static const T lowest_value(const T& a_arg)
00202 {
00203         T value;
00204 
00205         value = lowest_value<T>();
00206 
00207         return(value);
00208 }
00209 
00210 // ---------------------------------------------------------------------------
00211 
00212 /** Return the absolute value of a numeric type 
00213  *
00214  * Caveat: For some types, the maximum negative value is one larger than the
00215  * maximum positive value: specifically char.  Depending on the type and value,
00216  * it may be impossible to return the absolute value.  For such types under
00217  * such circumstances an exception is thrown.
00218  */
00219 template<typename T>
00220 T absolute(const T& a_num)
00221 {
00222         T num;
00223         std::string es;
00224 
00225         num = a_num;
00226         if (num < 0) {
00227                 num = -num;
00228                 if (num < 0) {
00229                         TRY_nomem(es = "Absolute value is still negative: ");
00230                         if (is_char(num)) {
00231                                 TRY_nomem(es += estring(static_cast<int>(num)));
00232                         }
00233                         else {
00234                                 TRY_nomem(es += estring(num));
00235                         }
00236                         throw(INTERNAL_ERROR(0,es));
00237                 }
00238         }
00239 
00240         return(num);
00241 }
00242 
00243 // ---------------------------------------------------------------------------
00244 
00245 /** Safely manipulate numbers without worryiung about over/underflow error */
00246 template<typename T>
00247 class safe_num
00248 {
00249 public:
00250         /** C'tor */
00251         safe_num()
00252         {
00253                 clear();
00254         }
00255 
00256         /** C'tor */
00257         safe_num(const T a_num)
00258         {
00259                 clear();
00260                 m_num = a_num;
00261         }
00262 
00263         /** C'tor */
00264         safe_num(const safe_num& a_class)
00265         {
00266                 clear();
00267                 m_num = a_class.value();
00268         }
00269 
00270         /** Clear the value */
00271         void clear(void)
00272         {
00273                 m_num = static_cast<T>(0);
00274         }
00275 
00276         /** Return the value */
00277         const T value(void) const
00278         {
00279                 return(m_num);
00280         }
00281 
00282         /** Assign a value */
00283         void assign(const T& a_arg)
00284         {
00285                 m_num = a_arg;
00286         }
00287 
00288         /** Add a value */
00289         void add(const T& a_arg) 
00290         {
00291                 bool overflow = false;
00292                 T num;
00293 
00294                 if (a_arg < static_cast<T>(0)) {
00295                         num = absolute(a_arg);
00296                         subtract(num);
00297                         return;
00298                 }
00299 
00300                 if (highest_value<T>() - a_arg < m_num)
00301                         overflow = true;
00302 
00303                 if (overflow) {
00304                         estring es;
00305 
00306                         es = "Addition overflow error detected: ";
00307                         if (is_char(m_num))
00308                                 es += estring(static_cast<int>(m_num));
00309                         else
00310                                 es += estring(m_num);
00311                         es += " + ";
00312                         if (is_char(a_arg))
00313                                 es += estring(static_cast<int>(a_arg));
00314                         else
00315                                 es += estring(a_arg);
00316                         throw(INTERNAL_ERROR(0,es));
00317                 }
00318                 m_num += a_arg;
00319         }
00320 
00321         /** Subtract a value */
00322         void subtract(const T& a_arg) 
00323         {
00324                 bool underflow = false;
00325                 T num;
00326 
00327                 if (a_arg < static_cast<T>(0)) {
00328                         num = absolute(a_arg);
00329                         add(num);
00330                         return;
00331                 }
00332 
00333                 if (lowest_value<T>() < 0) {
00334                         if (m_num < lowest_value<T>() + a_arg)
00335                                 underflow = true;
00336                 }
00337                 else {
00338                         if (m_num - lowest_value<T>() < a_arg)
00339                                 underflow = true;
00340                 }
00341 
00342                 if (underflow) {
00343                         estring es;
00344 
00345                         es = "Subtraction underflow error detected: ";
00346                         if (is_char(m_num))
00347                                 es += estring(static_cast<int>(m_num));
00348                         else
00349                                 es += estring(m_num);
00350                         es += " - ";
00351                         if (is_char(a_arg))
00352                                 es += estring(static_cast<int>(a_arg));
00353                         else
00354                                 es += estring(a_arg);
00355                         throw(INTERNAL_ERROR(0,es));
00356                 }
00357                 m_num -= a_arg;
00358         }
00359 
00360         /** Multiply by a value */
00361         void multiply(const T& a_arg) 
00362         {
00363                 bool overflow = false;
00364 
00365                 if ((a_arg == 0) || (m_num == 0) || (a_arg == 1) || (m_num == 1)) {
00366                         m_num *= a_arg;
00367                         return;
00368                 }
00369 
00370                 if ((lowest_value<T>() < 0) && (m_num < 0) && (a_arg < 0)) {
00371                         if (-highest_value<T>() > a_arg)
00372                                 overflow = true;
00373                         if (-(highest_value<T>() / a_arg) < -m_num)
00374                                 overflow = true;
00375                 }
00376                 else
00377                 if ((lowest_value<T>() < 0) && (m_num < 0) && (a_arg >= 0)) {
00378                         if (lowest_value<T>() / a_arg > m_num)
00379                                 overflow = true;
00380                 }
00381                 else
00382                 if ((lowest_value<T>() < 0) && (m_num >= 0) && (a_arg < 0)) {
00383                         if (lowest_value<T>() / m_num > a_arg)
00384                                 overflow = true;
00385                 }
00386                 else
00387                 if ((lowest_value<T>() < 0) && (m_num >= 0) && (a_arg >= 0)) {
00388                         if (highest_value<T>() / a_arg < m_num)
00389                                 overflow = true;
00390                 }
00391                 else
00392                 if ((lowest_value<T>() >= 0) && (m_num >= 0) && (a_arg >= 0)) {
00393                         if (highest_value<T>() / a_arg < m_num)
00394                                 overflow = true;
00395                 }
00396                 else {
00397                         // This should never happen
00398                         ASSERT(0);
00399                 }
00400 
00401                 if (overflow) {
00402                         estring es;
00403 
00404                         es = "Multiplication overflow error detected: ";
00405                         if (is_char(m_num))
00406                                 es += estring(static_cast<int>(m_num));
00407                         else
00408                                 es += estring(m_num);
00409                         es += " * ";
00410                         if (is_char(a_arg))
00411                                 es += estring(static_cast<int>(a_arg));
00412                         else
00413                                 es += estring(a_arg);
00414                         throw(INTERNAL_ERROR(0,es));
00415                 }
00416                 m_num *= a_arg;
00417         }
00418 
00419         /** Divide by a value */
00420         void divide(const T& a_arg) 
00421         {
00422                 T num;
00423 
00424                 if (a_arg == static_cast<T>(0)) {
00425                         estring es;
00426 
00427                         es = "Division by zero error detected: ";
00428                         if (is_char(m_num))
00429                                 es += estring(static_cast<int>(m_num));
00430                         else
00431                                 es += estring(m_num);
00432                         es += " / ";
00433                         if (is_char(a_arg))
00434                                 es += estring(static_cast<int>(a_arg));
00435                         else
00436                                 es += estring(a_arg);
00437                         throw(INTERNAL_ERROR(0,es));
00438                 }
00439 
00440                 num = m_num;
00441                 num /= a_arg;
00442                 if ((m_num < 0) && (a_arg < 0) && (num < 0)) {
00443                         estring es;
00444 
00445                         es = "Division result has incorrect sign: ";
00446                         if (is_char(m_num))
00447                                 es += estring(static_cast<int>(m_num));
00448                         else
00449                                 es += estring(m_num);
00450                         es += " / ";
00451                         if (is_char(a_arg))
00452                                 es += estring(static_cast<int>(a_arg));
00453                         else
00454                                 es += estring(a_arg);
00455                         es += " != ";
00456                         if (is_char(num))
00457                                 es += estring(static_cast<int>(num));
00458                         else
00459                                 es += estring(num);
00460                         throw(INTERNAL_ERROR(0,es));
00461                 }
00462 
00463                 m_num = num;
00464                 return;
00465         }
00466 
00467         /** Assign a safe_num */
00468         void assign(const safe_num<T>& a_class) 
00469         {
00470                 assign(a_class.value());
00471         }
00472 
00473         /** Add a safe_num */
00474         void add(const safe_num<T>& a_class) 
00475         {
00476                 add(a_class.value());
00477         }
00478 
00479         /** Subtract a safe_num */
00480         void subtract(const safe_num<T>& a_class)
00481         {
00482                 subtract(a_class.value());
00483         }
00484 
00485         /** Multiply by a safe_num */
00486         void multiply(const safe_num<T>& a_class) 
00487         {
00488                 multiply(a_class.value());
00489         }
00490 
00491         /** Divide by a safe_num */
00492         void divide(const safe_num<T>& a_class)
00493         {
00494                 divide(a_class.value());
00495         }
00496 
00497         /** Boolean operator */
00498         const bool operator==(const T& a_arg) const 
00499         {
00500                 bool value;
00501 
00502                 value = (m_num == a_arg);
00503 
00504                 return(value);
00505         }
00506 
00507         /** Boolean operator */
00508         const bool operator==(const safe_num<T>& a_class) const 
00509         {
00510                 bool value;
00511 
00512                 value = (m_num == a_class.value());
00513 
00514                 return(value);
00515         }
00516 
00517         /** Boolean operator */
00518         const bool operator!=(const T& a_arg) const
00519         {
00520                 bool value;
00521 
00522                 value = (m_num != a_arg);
00523 
00524                 return(value);
00525         }
00526 
00527         /** Boolean operator */
00528         const bool operator!=(const safe_num<T>& a_class) const
00529         {
00530                 bool value;
00531 
00532                 value = (m_num != a_class.value());
00533 
00534                 return(value);
00535         }
00536 
00537         /** Boolean operator */
00538         const bool operator<(const T& a_arg) const 
00539         {
00540                 bool value;
00541 
00542                 value = (m_num < a_arg);
00543 
00544                 return(value);
00545         }
00546 
00547         /** Boolean operator */
00548         const bool operator<(const safe_num<T>& a_class) const
00549         {
00550                 bool value;
00551 
00552                 value = (m_num < a_class.value());
00553 
00554                 return(value);
00555         }
00556 
00557         /** Boolean operator */
00558         const bool operator>(const T& a_arg) const
00559         {
00560                 bool value;
00561 
00562                 value = (m_num > a_arg);
00563 
00564                 return(value);
00565         }
00566 
00567         /** Boolean operator */
00568         const bool operator>(const safe_num<T>& a_class) const 
00569         {
00570                 bool value;
00571 
00572                 value = (m_num > a_class.value());
00573 
00574                 return(value);
00575         }
00576 
00577         /** Boolean operator */
00578         const bool operator<=(const T& a_arg) const
00579         {
00580                 bool value;
00581 
00582                 value = (m_num <= a_arg);
00583 
00584                 return(value);
00585         }
00586 
00587         /** Boolean operator */
00588         const bool operator<=(const safe_num<T>& a_class) const
00589         {
00590                 bool value;
00591 
00592                 value = (m_num <= a_class.value());
00593 
00594                 return(value);
00595         }
00596 
00597         /** Boolean operator */
00598         const bool operator>=(const T& a_arg) const
00599         {
00600                 bool value;
00601 
00602                 value = (m_num >= a_arg);
00603 
00604                 return(value);
00605         }
00606 
00607         /** Boolean operator */
00608         const bool operator>=(const safe_num<T>& a_class) const
00609         {
00610                 bool value;
00611 
00612                 value = (m_num >= a_class.value());
00613 
00614                 return(value);
00615         }
00616 
00617         /** Arithmetic operator */
00618         safe_num<T>& operator+=(safe_num<T> a_class)
00619         {
00620                 add(a_class);
00621 
00622                 return(*this);
00623         }
00624 
00625         /** Arithmetic operator */
00626         safe_num<T>& operator-=(safe_num<T> a_class)
00627         {
00628                 subtract(a_class);
00629 
00630                 return(*this);
00631         }
00632 
00633         /** Arithmetic operator */
00634         safe_num<T>& operator*=(safe_num<T> a_class)
00635         {
00636                 multiply(a_class);
00637 
00638                 return(*this);
00639         }
00640 
00641         /** Arithmetic operator */
00642         safe_num<T>& operator/=(safe_num<T> a_class)
00643         {
00644                 divide(a_class);
00645 
00646                 return(*this);
00647         }
00648 
00649         /** Arithmetic operator */
00650         safe_num<T>& operator%=(safe_num<T> a_class)
00651         {
00652                 m_num %= a_class.value();
00653 
00654                 return(*this);
00655         }
00656 
00657 private:
00658         T m_num;
00659 };
00660 
00661 /** Arithmetic operator */
00662 template<typename T>
00663 safe_num<T> operator+(safe_num<T> a_class1, safe_num<T> a_class2)
00664 {
00665         safe_num<T> result;
00666 
00667         result.assign(a_class1);
00668         result.add(a_class2);
00669 
00670         return(result);
00671 }
00672 
00673 /** Arithmetic operator */
00674 template<typename T>
00675 safe_num<T> operator-(safe_num<T> a_class1, safe_num<T> a_class2)
00676 {
00677         safe_num<T> result;
00678 
00679         result.assign(a_class1);
00680         result.subtract(a_class2);
00681         
00682         return(result);
00683 }
00684 
00685 /** Arithmetic operator */
00686 template<typename T>
00687 safe_num<T> operator*(safe_num<T> a_class1, safe_num<T> a_class2)
00688 {
00689         safe_num<T> result;
00690 
00691         result.assign(a_class1);
00692         result.multiply(a_class2);
00693 
00694         return(result);
00695 }
00696 
00697 /** Arithmetic operator */
00698 template<typename T>
00699 safe_num<T> operator/(safe_num<T> a_class1, safe_num<T> a_class2)
00700 {
00701         safe_num<T> result;
00702 
00703         result.assign(a_class1);
00704         result.divide(a_class2);
00705 
00706         return(result);
00707 }
00708 
00709 /** Arithmetic operator */
00710 template<typename T>
00711 safe_num<T> operator%(safe_num<T> a_class1, safe_num<T> a_class2)
00712 {
00713         safe_num<T> result;
00714 
00715         result.assign(a_class1.value() % a_class2.value());
00716 
00717         return(result);
00718 }
00719 
00720 /** Arithmetic operator */
00721 template<typename T>
00722 safe_num<T>& operator++(safe_num<T>& a_class)
00723 {
00724         a_class.add(static_cast<T>(1));
00725 
00726         return(a_class);
00727 }
00728 
00729 /** Arithmetic operator */
00730 template<typename T>
00731 safe_num<T> operator++(safe_num<T>& a_class, int)
00732 {
00733         safe_num<T> result;
00734 
00735         result.assign(a_class);
00736         a_class.add(static_cast<T>(1));
00737 
00738         return(result);
00739 }
00740 
00741 /** Arithmetic operator */
00742 template<typename T>
00743 safe_num<T>& operator--(safe_num<T>& a_class)
00744 {
00745         a_class.subtract(static_cast<T>(1));
00746 
00747         return(a_class);
00748 }
00749 
00750 /** Arithmetic operator */
00751 template<typename T>
00752 safe_num<T> operator--(safe_num<T>& a_class, int)
00753 {
00754         safe_num<T> result;
00755 
00756         result.assign(a_class);
00757         a_class.subtract(static_cast<T>(1));
00758 
00759         return(result);
00760 }
00761 
00762 /** Arithmetic operator */
00763 template<typename T>
00764 std::ostream& operator<<(std::ostream& a_out, safe_num<T> a_class)
00765 {
00766         a_out << a_class.value();
00767 
00768         return(a_out);
00769 }
00770 
00771 /** Arithmetic operator */
00772 template<typename T>
00773 std::istream& operator>>(std::istream& a_in, safe_num<T>& a_class)
00774 {
00775         T num;
00776 
00777         a_in >> num;
00778         a_class = num;
00779 
00780         return(a_in);
00781 }
00782 
00783 // ---------------------------------------------------------------------------
00784 
00785 #endif

Generated on Wed Jun 21 10:50:04 2006 for rvm by  doxygen 1.4.2