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
00012
00013
00014
00015
00016
00017
00018
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
00044
00045
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
00081 template<>
00082 static const float max_limit<float>()
00083 {
00084 return(FLT_MAX);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094 template<>
00095 static const float min_limit<float>()
00096 {
00097 return(FLT_MIN);
00098 }
00099
00100
00101 template<>
00102 static const double max_limit<double>()
00103 {
00104 return(DBL_MAX);
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114 template<>
00115 static const double min_limit<double>()
00116 {
00117 return(DBL_MIN);
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
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
00139
00140
00141
00142
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
00157
00158
00159
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
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
00183
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
00198
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
00213
00214
00215
00216
00217
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
00246 template<typename T>
00247 class safe_num
00248 {
00249 public:
00250
00251 safe_num()
00252 {
00253 clear();
00254 }
00255
00256
00257 safe_num(const T a_num)
00258 {
00259 clear();
00260 m_num = a_num;
00261 }
00262
00263
00264 safe_num(const safe_num& a_class)
00265 {
00266 clear();
00267 m_num = a_class.value();
00268 }
00269
00270
00271 void clear(void)
00272 {
00273 m_num = static_cast<T>(0);
00274 }
00275
00276
00277 const T value(void) const
00278 {
00279 return(m_num);
00280 }
00281
00282
00283 void assign(const T& a_arg)
00284 {
00285 m_num = a_arg;
00286 }
00287
00288
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
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
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
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
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
00468 void assign(const safe_num<T>& a_class)
00469 {
00470 assign(a_class.value());
00471 }
00472
00473
00474 void add(const safe_num<T>& a_class)
00475 {
00476 add(a_class.value());
00477 }
00478
00479
00480 void subtract(const safe_num<T>& a_class)
00481 {
00482 subtract(a_class.value());
00483 }
00484
00485
00486 void multiply(const safe_num<T>& a_class)
00487 {
00488 multiply(a_class.value());
00489 }
00490
00491
00492 void divide(const safe_num<T>& a_class)
00493 {
00494 divide(a_class.value());
00495 }
00496
00497
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
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
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
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
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
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
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
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
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
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
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
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
00618 safe_num<T>& operator+=(safe_num<T> a_class)
00619 {
00620 add(a_class);
00621
00622 return(*this);
00623 }
00624
00625
00626 safe_num<T>& operator-=(safe_num<T> a_class)
00627 {
00628 subtract(a_class);
00629
00630 return(*this);
00631 }
00632
00633
00634 safe_num<T>& operator*=(safe_num<T> a_class)
00635 {
00636 multiply(a_class);
00637
00638 return(*this);
00639 }
00640
00641
00642 safe_num<T>& operator/=(safe_num<T> a_class)
00643 {
00644 divide(a_class);
00645
00646 return(*this);
00647 }
00648
00649
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
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
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
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
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
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
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
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
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
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
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
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