rvm 1.08

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