00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #define DTBUG1490 (1)
00040
00041 #include "fennel/common/CommonPreamble.h"
00042
00043 #include <assert.h>
00044 #ifndef DTBUG1490
00045 #pragma STDC FENV_ACCESS ON
00046
00047
00048
00049
00050 #endif
00051 #ifndef __MSVC__
00052 #include <fenv.h>
00053 #endif
00054 #include <string>
00055
00056 #include "NoisyArithmetic.h"
00057
00058 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/calculator/NoisyArithmetic.cpp#3 $");
00059
00060
00061
00062 #ifdef __MSVC__
00063 #define NOISY_DISABLED (1)
00064 #endif
00065
00066
00067 #define S_OVER "22003"
00068 #define S_UNDR "22000"
00069 #define S_INVL "22023"
00070 #define S_INEX "22000"
00071 #define S_DIV0 "22012"
00072
00073
00074 static void Raise(
00075 TExceptionCBData *pData,
00076 TProgramCounter pc,
00077 const char *pMsg)
00078 throw(CalcMessage)
00079 {
00080 if (pData) {
00081 assert(pData->fnCB);
00082 (pData->fnCB)(pMsg, pData->pData);
00083 }
00084 throw CalcMessage(pMsg, pc);
00085 }
00086
00087 #if defined(NOISY_DISABLED) && NOISY_DISABLED
00088
00089
00090
00091
00092 #define DO(type) \
00093 template <> type Noisy<type>::add( \
00094 TProgramCounter, \
00095 const type left, const type right, \
00096 TExceptionCBData *pExData) throw(CalcMessage) \
00097 { \
00098 return left + right; \
00099 } \
00100 template <> type Noisy<type>::sub( \
00101 TProgramCounter, \
00102 const type left, const type right, \
00103 TExceptionCBData *pExData) throw(CalcMessage) \
00104 { \
00105 return left - right; \
00106 } \
00107 template <> type Noisy<type>::mul( \
00108 TProgramCounter, \
00109 const type left, const type right, \
00110 TExceptionCBData *pExData) throw(CalcMessage) \
00111 { \
00112 return left * right; \
00113 } \
00114 template <> type Noisy<type>::div( \
00115 TProgramCounter pc, \
00116 const type left, const type right, \
00117 TExceptionCBData *pExData) throw(CalcMessage) { \
00118 if (right == 0) { \
00119 Raise(pExData, pc, S_DIV0); \
00120 } \
00121 return left / right; \
00122 } \
00123 template <> type Noisy<type>::neg( \
00124 TProgramCounter, \
00125 const type right, \
00126 TExceptionCBData *pExData) throw(CalcMessage) \
00127 { \
00128 return right * -1; \
00129 }
00130 DO(char)
00131 DO(signed char)
00132 DO(unsigned char)
00133 DO(short)
00134 DO(unsigned short)
00135 DO(int)
00136 DO(unsigned int)
00137 #if __WORDSIZE == 64
00138 DO(long int)
00139 DO(long unsigned int)
00140 #else
00141 DO(long long int)
00142 DO(long long unsigned int)
00143 #endif
00144 DO(float)
00145 DO(double)
00146 DO(long double)
00147
00148 #else
00149 #define UNSIGNED_ADD(type) \
00150 template <> type Noisy<type>::add( \
00151 TProgramCounter pc, const type left, \
00152 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00153 { \
00154 register type result; \
00155 if (left > (std::numeric_limits<type>::max() - right)) { \
00156 Raise(pExData, pc, S_OVER); \
00157 } \
00158 result = left + right; \
00159 assert(result == (left + right)); \
00160 return result; \
00161 }
00162
00163 #define SIGNED_ADD(type) \
00164 template <> type Noisy<type>::add( \
00165 TProgramCounter pc, const type left, \
00166 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00167 { \
00168 register type result = left + right; \
00169 if (left < 0 && right < 0 && result >=0) { \
00170 Raise(pExData, pc, S_OVER); \
00171 } \
00172 if (left > 0 && right > 0 && result <= 0) { \
00173 Raise(pExData, pc, S_OVER); \
00174 } \
00175 assert(result == (left + right)); \
00176 return result; \
00177 }
00178
00179 #define UNSIGNED_SUB(type) \
00180 template <> type Noisy<type>::sub( \
00181 TProgramCounter pc, const type left, \
00182 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00183 { \
00184 register type result; \
00185 if (right > left) { \
00186 Raise(pExData, pc, S_OVER); \
00187 } \
00188 return left - right; \
00189 result = left - right; \
00190 assert(result == (left - right)); \
00191 return result; \
00192 }
00193
00194 #define SIGNED_SUB(type) \
00195 template <> type Noisy<type>::sub( \
00196 TProgramCounter pc, const type left, \
00197 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00198 { \
00199 register type r = right; \
00200 register type l = left; \
00201 register type result; \
00202 if (r == std::numeric_limits<type>::min()) { \
00203 if (l == std::numeric_limits<type>::max()) { \
00204 Raise(pExData, pc, S_OVER); \
00205 } \
00206 r++; \
00207 l++; \
00208 } \
00209 result = Noisy<type>::add(pc, l, -r, pExData); \
00210 assert(result == (left - right)); \
00211 return result; \
00212 }
00213
00214 #define UNSIGNED_MUL(type) \
00215 template <> type Noisy<type>::mul( \
00216 TProgramCounter pc, const type left, \
00217 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00218 { \
00219 register type result; \
00220 if (left == 0 || right == 0) { \
00221 return 0; \
00222 } \
00223 if (left > right) { \
00224 return Noisy<type>::mul(pc, right, left, pExData); \
00225 } \
00226 register type r = right; \
00227 register type l = left; \
00228 assert(l <= r); \
00229 const type msb = ~(std::numeric_limits<type>::max() >> 1); \
00230 result = 0; \
00231 while (1) { \
00232 if (l & 0x1) { \
00233 result = Noisy<type>::add(pc, result, r, pExData); \
00234 } \
00235 l >>= 1; \
00236 if (!l) { \
00237 break; \
00238 } \
00239 if (msb & r) { \
00240 Raise(pExData, pc, S_OVER); \
00241 } \
00242 r <<= 1; \
00243 } \
00244 assert(result == (left * right)); \
00245 return result; \
00246 }
00247
00248 #define SIGNED_MUL(type) \
00249 template <> type Noisy<type>::mul( \
00250 TProgramCounter pc, const type left, \
00251 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00252 { \
00253 register type result; \
00254 if (left == 0 || right == 0) { \
00255 return 0; \
00256 } \
00257 if (right > left) { \
00258 return Noisy<type>::mul(pc, right, left, pExData); \
00259 } \
00260 register type r = right; \
00261 register type l = left; \
00262 assert(r <= l); \
00263 if (l < 0 ) { \
00264 if (r == std::numeric_limits<type>::min()) { \
00265 Raise(pExData, pc, S_OVER); \
00266 } \
00267 assert(l != std::numeric_limits<type>::min()); \
00268 l = -l; \
00269 r = -r; \
00270 } \
00271 assert(l > 0); \
00272 const type n_max = std::numeric_limits<type>::min() >> 1; \
00273 const type p_max = (-n_max) - 1; \
00274 result = 0; \
00275 while (1) { \
00276 if (l & 0x1) { \
00277 result=Noisy<type>::add(pc, result, r, pExData); \
00278 } \
00279 l >>= 1; \
00280 if (!l) { \
00281 break; \
00282 } \
00283 if (r < n_max || r > p_max) { \
00284 Raise(pExData, pc, S_OVER); \
00285 } \
00286 r *= 2; \
00287 } \
00288 assert(result == (left * right)); \
00289 return result; \
00290 }
00291
00292 #define UNSIGNED_DIV(type) \
00293 template <> type Noisy<type>::div( \
00294 TProgramCounter pc, const type left, \
00295 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00296 { \
00297 if (right == 0) { \
00298 Raise(pExData, pc, S_DIV0); \
00299 } \
00300 register type result = left / right; \
00301 assert(result == (left / right)); \
00302 return result; \
00303 }
00304
00305 #define SIGNED_DIV(type) \
00306 template <> type Noisy<type>::div( \
00307 TProgramCounter pc, const type left, \
00308 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00309 { \
00310 \
00311 if (left == std::numeric_limits<type>::min() && right == -1) { \
00312 Raise(pExData, pc, S_OVER); \
00313 } \
00314 if (right == 0) { \
00315 Raise(pExData, pc, S_DIV0); \
00316 } \
00317 register type result = left / right; \
00318 assert(result == (left / right)); \
00319 return result; \
00320 }
00321
00322 #define UNSIGNED_NEG(type) \
00323 template <> type Noisy<type>::neg( \
00324 TProgramCounter pc, \
00325 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00326 { \
00327 if (right != 0) { \
00328 Raise(pExData, pc, S_OVER); \
00329 } \
00330 return 0; \
00331 }
00332
00333 #define SIGNED_NEG(type) \
00334 template <> type Noisy<type>::neg( \
00335 TProgramCounter pc, \
00336 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00337 { \
00338 \
00339 if (right == std::numeric_limits<type>::min()) { \
00340 Raise(pExData, pc, S_OVER); \
00341 } \
00342 return -(right); \
00343 }
00344
00345
00346 inline void maybe_raise_fe_exception(
00347 TExceptionCBData *pExData,
00348 TProgramCounter pc)
00349 throw(CalcMessage)
00350 {
00351 int fe = ::fetestexcept(FE_ALL_EXCEPT);
00352 if (0) {
00353 } else if (fe & FE_DIVBYZERO) {
00354 Raise(pExData, pc, S_DIV0);
00355 } else if (fe & FE_UNDERFLOW) {
00356 Raise(pExData, pc, S_UNDR);
00357 } else if (fe & FE_OVERFLOW) {
00358 Raise(pExData, pc, S_OVER);
00359 } else if (fe & FE_INVALID) {
00360 Raise(pExData, pc, S_INVL);
00361
00362
00363
00364 } else if (fe & FE_INEXACT) {
00365
00366
00367
00368 }
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 #if defined(DTBUG1490) && DTBUG1490
00384
00385
00386 # define OP_FN_PROLOG static void __attribute__((noinline))
00387 #else
00388
00389 # define inline void
00390 #endif
00391 template <typename TYPE> OP_FN_PROLOG na_add(
00392 TYPE &res, const TYPE &r, const TYPE &l)
00393 {
00394 res = r + l;
00395 }
00396
00397 template <typename TYPE> OP_FN_PROLOG na_sub(
00398 TYPE &res, const TYPE &r, const TYPE &l)
00399 {
00400 res = r - l;
00401 }
00402
00403 template <typename TYPE> OP_FN_PROLOG na_mul(
00404 TYPE &res, const TYPE &r, const TYPE &l)
00405 {
00406 res = r * l;
00407 }
00408
00409 template <typename TYPE> OP_FN_PROLOG na_div(
00410 TYPE &res, const TYPE &r, const TYPE &l)
00411 {
00412 res = r / l;
00413 }
00414
00415 template <typename TYPE> OP_FN_PROLOG na_neg(TYPE &res, const TYPE &r)
00416 {
00417 res = -r;
00418 }
00419
00420 #define FLOATING_ADD(type) \
00421 template <> type Noisy<type>::add( \
00422 TProgramCounter pc, const type left, \
00423 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00424 { \
00425 type result; \
00426 ::feclearexcept(FE_ALL_EXCEPT); \
00427 na_add<type>(result, left, right); \
00428 maybe_raise_fe_exception(pExData, pc); \
00429 return result; \
00430 }
00431
00432 #define FLOATING_SUB(type) \
00433 template <> type Noisy<type>::sub( \
00434 TProgramCounter pc, const type left, \
00435 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00436 { \
00437 type result; \
00438 ::feclearexcept(FE_ALL_EXCEPT); \
00439 na_sub<type>(result, left, right); \
00440 maybe_raise_fe_exception(pExData, pc); \
00441 return result; \
00442 }
00443
00444 #define FLOATING_MUL(type) \
00445 template <> type Noisy<type>::mul( \
00446 TProgramCounter pc, const type left, \
00447 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00448 { \
00449 type result; \
00450 ::feclearexcept(FE_ALL_EXCEPT); \
00451 na_mul<type>(result, left, right); \
00452 maybe_raise_fe_exception(pExData, pc); \
00453 return result; \
00454 }
00455
00456 #define FLOATING_DIV(type) \
00457 template <> type Noisy<type>::div( \
00458 TProgramCounter pc, const type left, \
00459 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00460 { \
00461 type result; \
00462 ::feclearexcept(FE_ALL_EXCEPT); \
00463 na_div<type>(result, left, right); \
00464 maybe_raise_fe_exception(pExData, pc); \
00465 return result; \
00466 }
00467
00468 #define FLOATING_NEG(type) \
00469 template <> type Noisy<type>::neg( \
00470 TProgramCounter pc, \
00471 const type right, TExceptionCBData *pExData) throw(CalcMessage) \
00472 { \
00473 type result; \
00474 ::feclearexcept(FE_ALL_EXCEPT); \
00475 result = (-right); \
00476 na_neg<type>(result, right); \
00477 maybe_raise_fe_exception(pExData, pc); \
00478 return result; \
00479 }
00480
00481 SIGNED_ADD(char)
00482 SIGNED_ADD(signed char)
00483 SIGNED_ADD(short)
00484 SIGNED_ADD(int)
00485 SIGNED_ADD(long long int)
00486
00487 UNSIGNED_ADD(unsigned char)
00488 UNSIGNED_ADD(unsigned short)
00489 UNSIGNED_ADD(unsigned int)
00490 UNSIGNED_ADD(unsigned long long int)
00491
00492 SIGNED_SUB(char)
00493 SIGNED_SUB(signed char)
00494 SIGNED_SUB(short)
00495 SIGNED_SUB(int)
00496 SIGNED_SUB(long long int)
00497
00498 UNSIGNED_SUB(unsigned char)
00499 UNSIGNED_SUB(unsigned short)
00500 UNSIGNED_SUB(unsigned int)
00501 UNSIGNED_SUB(unsigned long long int)
00502
00503 SIGNED_MUL(char)
00504 SIGNED_MUL(signed char)
00505 SIGNED_MUL(short)
00506 SIGNED_MUL(int)
00507 SIGNED_MUL(long long int)
00508
00509 UNSIGNED_MUL(unsigned char)
00510 UNSIGNED_MUL(unsigned short)
00511 UNSIGNED_MUL(unsigned int)
00512 UNSIGNED_MUL(unsigned long long int)
00513
00514 SIGNED_DIV(char)
00515 SIGNED_DIV(signed char)
00516 SIGNED_DIV(short)
00517 SIGNED_DIV(int)
00518 SIGNED_DIV(long long int)
00519
00520 SIGNED_NEG(char)
00521 SIGNED_NEG(signed char)
00522 SIGNED_NEG(short)
00523 SIGNED_NEG(int)
00524 SIGNED_NEG(long long int)
00525
00526 UNSIGNED_DIV(unsigned char)
00527 UNSIGNED_DIV(unsigned short)
00528 UNSIGNED_DIV(unsigned int)
00529 UNSIGNED_DIV(unsigned long long int)
00530
00531 UNSIGNED_NEG(unsigned char)
00532 UNSIGNED_NEG(unsigned short)
00533 UNSIGNED_NEG(unsigned int)
00534 UNSIGNED_NEG(unsigned long long int)
00535
00536 #if __WORDSIZE == 64
00537 SIGNED_ADD(long int)
00538 UNSIGNED_ADD(unsigned long int)
00539 SIGNED_SUB(long int)
00540 UNSIGNED_SUB(unsigned long int)
00541 SIGNED_MUL(long int)
00542 UNSIGNED_MUL(unsigned long int)
00543 SIGNED_DIV(long int)
00544 SIGNED_NEG(long int)
00545 UNSIGNED_DIV(unsigned long int)
00546 UNSIGNED_NEG(unsigned long int)
00547 #endif
00548
00549 FLOATING_ADD(float)
00550 FLOATING_ADD(double)
00551 FLOATING_ADD(long double)
00552
00553 FLOATING_SUB(float)
00554 FLOATING_SUB(double)
00555 FLOATING_SUB(long double)
00556
00557 FLOATING_MUL(float)
00558 FLOATING_MUL(double)
00559 FLOATING_MUL(long double)
00560
00561 FLOATING_DIV(float)
00562 FLOATING_DIV(double)
00563 FLOATING_DIV(long double)
00564
00565 FLOATING_NEG(float)
00566 FLOATING_NEG(double)
00567 FLOATING_NEG(long double)
00568
00569 #undef UNSIGNED_ADD
00570 #undef SIGNED_ADD
00571 #undef FLOATING_ADD
00572 #undef UNSIGNED_SUB
00573 #undef SIGNED_SUB
00574 #undef FLOATING_SUB
00575 #undef UNSIGNED_MUL
00576 #undef SIGNED_MUL
00577 #undef FLOATING_MUL
00578 #undef UNSIGNED_DIV
00579 #undef SIGNED_DIV
00580 #undef FLOATING_DIV
00581 #undef UNSIGNED_NEG
00582 #undef SIGNED_NEG
00583 #undef FLOATING_NEG
00584
00585 #endif
00586
00587 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/calculator/NoisyArithmetic.cpp#3 $");
00588
00589