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 const float max_limit<float>()
00083 {
00084 return(FLT_MAX);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094 template<>
00095 const float min_limit<float>()
00096 {
00097 return(FLT_MIN);
00098 }
00099
00100
00101 template<>
00102 const double max_limit<double>()
00103 {
00104 return(DBL_MAX);
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114 template<>
00115 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
00226 num = a_num;
00227 if ((num < 0) && (num == min_limit<T>())) {
00228 TRY_nomem(es = "Absolute value is not containable by this type: ");
00229 if (is_char(num)) {
00230 TRY_nomem(es += estring(static_cast<int>(num)));
00231 }
00232 else {
00233 TRY_nomem(es += estring(num));
00234 }
00235 throw(ERROR(0,es));
00236 }
00237 if (num < 0) {
00238 num = -num;
00239 if (num < 0) {
00240 TRY_nomem(es = "Absolute value is still negative: ");
00241 if (is_char(num)) {
00242 TRY_nomem(es += estring(static_cast<int>(num)));
00243 }
00244 else {
00245 TRY_nomem(es += estring(num));
00246 }
00247 throw(INTERNAL_ERROR(0,es));
00248 }
00249
00250 }
00251
00252
00253
00254 return(num);
00255 }
00256
00257
00258
00259
00260 template<typename T>
00261 class safe_num
00262 {
00263 public:
00264
00265 safe_num()
00266 {
00267 clear();
00268 }
00269
00270
00271 safe_num(const T a_num)
00272 {
00273 clear();
00274 m_num = a_num;
00275 }
00276
00277
00278 safe_num(const safe_num& a_class)
00279 {
00280 clear();
00281 m_num = a_class.value();
00282 }
00283
00284
00285 void clear(void)
00286 {
00287 m_num = static_cast<T>(0);
00288 }
00289
00290
00291 const T value(void) const
00292 {
00293 return(m_num);
00294 }
00295
00296
00297 void assign(const T& a_arg)
00298 {
00299 m_num = a_arg;
00300 }
00301
00302
00303 void add(const T& a_arg)
00304 {
00305 bool overflow = false;
00306 T num;
00307
00308 if (a_arg < static_cast<T>(0)) {
00309 num = absolute(a_arg);
00310 subtract(num);
00311 return;
00312 }
00313
00314 if (highest_value<T>() - a_arg < m_num)
00315 overflow = true;
00316
00317 if (overflow) {
00318 estring es;
00319
00320 es = "Addition overflow error detected: ";
00321 if (is_char(m_num))
00322 es += estring(static_cast<int>(m_num));
00323 else
00324 es += estring(m_num);
00325 es += " + ";
00326 if (is_char(a_arg))
00327 es += estring(static_cast<int>(a_arg));
00328 else
00329 es += estring(a_arg);
00330 throw(INTERNAL_ERROR(0,es));
00331 }
00332 m_num += a_arg;
00333 }
00334
00335
00336 void subtract(const T& a_arg)
00337 {
00338 bool underflow = false;
00339 T num;
00340
00341 if (a_arg < static_cast<T>(0)) {
00342 num = absolute(a_arg);
00343 add(num);
00344 return;
00345 }
00346
00347 if (lowest_value<T>() < 0) {
00348 if (m_num < lowest_value<T>() + a_arg)
00349 underflow = true;
00350 }
00351 else {
00352 if (m_num - lowest_value<T>() < a_arg)
00353 underflow = true;
00354 }
00355
00356 if (underflow) {
00357 estring es;
00358
00359 es = "Subtraction underflow error detected: ";
00360 if (is_char(m_num))
00361 es += estring(static_cast<int>(m_num));
00362 else
00363 es += estring(m_num);
00364 es += " - ";
00365 if (is_char(a_arg))
00366 es += estring(static_cast<int>(a_arg));
00367 else
00368 es += estring(a_arg);
00369 throw(INTERNAL_ERROR(0,es));
00370 }
00371 m_num -= a_arg;
00372 }
00373
00374
00375 void multiply(const T& a_arg)
00376 {
00377 bool overflow = false;
00378
00379 if ((a_arg == 0) || (m_num == 0) || (a_arg == 1) || (m_num == 1)) {
00380 m_num *= a_arg;
00381 return;
00382 }
00383
00384 if ((lowest_value<T>() < 0) && (m_num < 0) && (a_arg < 0)) {
00385 if (-highest_value<T>() > a_arg)
00386 overflow = true;
00387 if (-(highest_value<T>() / a_arg) < -m_num)
00388 overflow = true;
00389 }
00390 else
00391 if ((lowest_value<T>() < 0) && (m_num < 0) && (a_arg >= 0)) {
00392 if (lowest_value<T>() / a_arg > m_num)
00393 overflow = true;
00394 }
00395 else
00396 if ((lowest_value<T>() < 0) && (m_num >= 0) && (a_arg < 0)) {
00397 if (lowest_value<T>() / m_num > a_arg)
00398 overflow = true;
00399 }
00400 else
00401 if ((lowest_value<T>() < 0) && (m_num >= 0) && (a_arg >= 0)) {
00402 if (highest_value<T>() / a_arg < m_num)
00403 overflow = true;
00404 }
00405 else
00406 if ((lowest_value<T>() >= 0) && (m_num >= 0) && (a_arg >= 0)) {
00407 if (highest_value<T>() / a_arg < m_num)
00408 overflow = true;
00409 }
00410 else {
00411
00412 ASSERT(0);
00413 }
00414
00415 if (overflow) {
00416 estring es;
00417
00418 es = "Multiplication overflow error detected: ";
00419 if (is_char(m_num))
00420 es += estring(static_cast<int>(m_num));
00421 else
00422 es += estring(m_num);
00423 es += " * ";
00424 if (is_char(a_arg))
00425 es += estring(static_cast<int>(a_arg));
00426 else
00427 es += estring(a_arg);
00428 throw(INTERNAL_ERROR(0,es));
00429 }
00430 m_num *= a_arg;
00431 }
00432
00433
00434 void divide(const T& a_arg)
00435 {
00436 T num;
00437
00438 if (a_arg == static_cast<T>(0)) {
00439 estring es;
00440
00441 es = "Division by zero error detected: ";
00442 if (is_char(m_num))
00443 es += estring(static_cast<int>(m_num));
00444 else
00445 es += estring(m_num);
00446 es += " / ";
00447 if (is_char(a_arg))
00448 es += estring(static_cast<int>(a_arg));
00449 else
00450 es += estring(a_arg);
00451 throw(INTERNAL_ERROR(0,es));
00452 }
00453
00454 num = m_num;
00455 num /= a_arg;
00456 if ((m_num < 0) && (a_arg < 0) && (num < 0)) {
00457 estring es;
00458
00459 es = "Division result has incorrect sign: ";
00460 if (is_char(m_num))
00461 es += estring(static_cast<int>(m_num));
00462 else
00463 es += estring(m_num);
00464 es += " / ";
00465 if (is_char(a_arg))
00466 es += estring(static_cast<int>(a_arg));
00467 else
00468 es += estring(a_arg);
00469 es += " != ";
00470 if (is_char(num))
00471 es += estring(static_cast<int>(num));
00472 else
00473 es += estring(num);
00474 throw(INTERNAL_ERROR(0,es));
00475 }
00476
00477 m_num = num;
00478 return;
00479 }
00480
00481
00482 void assign(const safe_num<T>& a_class)
00483 {
00484 assign(a_class.value());
00485 }
00486
00487
00488 void add(const safe_num<T>& a_class)
00489 {
00490 add(a_class.value());
00491 }
00492
00493
00494 void subtract(const safe_num<T>& a_class)
00495 {
00496 subtract(a_class.value());
00497 }
00498
00499
00500 void multiply(const safe_num<T>& a_class)
00501 {
00502 multiply(a_class.value());
00503 }
00504
00505
00506 void divide(const safe_num<T>& a_class)
00507 {
00508 divide(a_class.value());
00509 }
00510
00511
00512 const bool operator==(const T& a_arg) const
00513 {
00514 bool value;
00515
00516 value = (m_num == a_arg);
00517
00518 return(value);
00519 }
00520
00521
00522 const bool operator==(const safe_num<T>& a_class) const
00523 {
00524 bool value;
00525
00526 value = (m_num == a_class.value());
00527
00528 return(value);
00529 }
00530
00531
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
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
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
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
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
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
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
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
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
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
00632 safe_num<T>& operator+=(safe_num<T> a_class)
00633 {
00634 add(a_class);
00635
00636 return(*this);
00637 }
00638
00639
00640 safe_num<T>& operator-=(safe_num<T> a_class)
00641 {
00642 subtract(a_class);
00643
00644 return(*this);
00645 }
00646
00647
00648 safe_num<T>& operator*=(safe_num<T> a_class)
00649 {
00650 multiply(a_class);
00651
00652 return(*this);
00653 }
00654
00655
00656 safe_num<T>& operator/=(safe_num<T> a_class)
00657 {
00658 divide(a_class);
00659
00660 return(*this);
00661 }
00662
00663
00664 safe_num<T>& operator%=(safe_num<T> a_class)
00665 {
00666 m_num %= a_class.value();
00667
00668 return(*this);
00669 }
00670
00671 private:
00672 T m_num;
00673 };
00674
00675
00676 template<typename T>
00677 safe_num<T> operator+(safe_num<T> a_class1, safe_num<T> a_class2)
00678 {
00679 safe_num<T> result;
00680
00681 result.assign(a_class1);
00682 result.add(a_class2);
00683
00684 return(result);
00685 }
00686
00687
00688 template<typename T>
00689 safe_num<T> operator-(safe_num<T> a_class1, safe_num<T> a_class2)
00690 {
00691 safe_num<T> result;
00692
00693 result.assign(a_class1);
00694 result.subtract(a_class2);
00695
00696 return(result);
00697 }
00698
00699
00700 template<typename T>
00701 safe_num<T> operator*(safe_num<T> a_class1, safe_num<T> a_class2)
00702 {
00703 safe_num<T> result;
00704
00705 result.assign(a_class1);
00706 result.multiply(a_class2);
00707
00708 return(result);
00709 }
00710
00711
00712 template<typename T>
00713 safe_num<T> operator/(safe_num<T> a_class1, safe_num<T> a_class2)
00714 {
00715 safe_num<T> result;
00716
00717 result.assign(a_class1);
00718 result.divide(a_class2);
00719
00720 return(result);
00721 }
00722
00723
00724 template<typename T>
00725 safe_num<T> operator%(safe_num<T> a_class1, safe_num<T> a_class2)
00726 {
00727 safe_num<T> result;
00728
00729 result.assign(a_class1.value() % a_class2.value());
00730
00731 return(result);
00732 }
00733
00734
00735 template<typename T>
00736 safe_num<T>& operator++(safe_num<T>& a_class)
00737 {
00738 a_class.add(static_cast<T>(1));
00739
00740 return(a_class);
00741 }
00742
00743
00744 template<typename T>
00745 safe_num<T> operator++(safe_num<T>& a_class, int)
00746 {
00747 safe_num<T> result;
00748
00749 result.assign(a_class);
00750 a_class.add(static_cast<T>(1));
00751
00752 return(result);
00753 }
00754
00755
00756 template<typename T>
00757 safe_num<T>& operator--(safe_num<T>& a_class)
00758 {
00759 a_class.subtract(static_cast<T>(1));
00760
00761 return(a_class);
00762 }
00763
00764
00765 template<typename T>
00766 safe_num<T> operator--(safe_num<T>& a_class, int)
00767 {
00768 safe_num<T> result;
00769
00770 result.assign(a_class);
00771 a_class.subtract(static_cast<T>(1));
00772
00773 return(result);
00774 }
00775
00776
00777 template<typename T>
00778 std::ostream& operator<<(std::ostream& a_out, safe_num<T> a_class)
00779 {
00780 a_out << a_class.value();
00781
00782 return(a_out);
00783 }
00784
00785
00786 template<typename T>
00787 std::istream& operator>>(std::istream& a_in, safe_num<T>& a_class)
00788 {
00789 T num;
00790
00791 a_in >> num;
00792 a_class = num;
00793
00794 return(a_in);
00795 }
00796
00797
00798
00799 #endif