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 #ifndef _FINRESDYN_OPENSINE_H_
00036 #define _FINRESDYN_OPENSINE_H_
00037
00038
00039
00040 #include "rounding.h"
00041 #include "numberpi.h"
00042
00043
00044
00045
00046
00047
00048
00049
00050 template <class NumType, int nTerms>
00051 class tOpenSine
00052 {
00053 public:
00054
00055 static int compute (const NumType &xLeft, const NumType &xRight,
00056 NumType &yLeft, NumType &yRight);
00057
00058 private:
00059
00060
00061 static void computeTaylorTerms (const NumType &x,
00062 NumType *lower_x2k, NumType *upper_x2k, int n);
00063
00064
00065
00066 static NumType lowerBoundTaylor (const NumType &x);
00067
00068
00069
00070 static NumType upperBoundTaylor (const NumType &x);
00071
00072
00073
00074 static int shifted1pi (const NumType &xLeft, const NumType &xRight,
00075 NumType &yLeft, NumType &yRight);
00076
00077
00078
00079 static int shifted2pi (const NumType &xLeft, const NumType &xRight,
00080 NumType &yLeft, NumType &yRight);
00081
00082 };
00083
00084
00085
00086 template <class NumType, int nTerms>
00087 inline void tOpenSine<NumType,nTerms>::computeTaylorTerms
00088 (const NumType &x, NumType *lower_x2k, NumType *upper_x2k, int n)
00089 {
00090
00091 typedef tRounding<NumType> rnd;
00092 typedef tNumberPi<NumType> pi;
00093
00094
00095 NumType lowerDiff = (x <= pi::lowerBound () / 2) ?
00096 rnd::sub_down (pi::lowerBound () / 2, x) :
00097 rnd::sub_down (x, pi::upperBound () / 2);
00098 if (lowerDiff < 0)
00099 lowerDiff = 0;
00100 NumType lower_x2 = rnd::mul_down (lowerDiff, lowerDiff);
00101 NumType upperDiff = (x <= pi::upperBound () / 2) ?
00102 rnd::sub_up (pi::upperBound () / 2, x) :
00103 rnd::sub_up (x, pi::lowerBound () / 2);
00104 NumType upper_x2 = rnd::mul_up (upperDiff, upperDiff);
00105
00106
00107
00108
00109 for (int k = 0; k < n; ++ k)
00110 {
00111 if (k == 0)
00112 {
00113 lower_x2k [0] = 1;
00114 upper_x2k [0] = 1;
00115 }
00116 else if (k == 1)
00117 {
00118 lower_x2k [1] = lower_x2 / 2;
00119 upper_x2k [1] = upper_x2 / 2;
00120 }
00121 else
00122 {
00123 long int factor = ((k << 1) - 1) * (k << 1);
00124 lower_x2k [k] = rnd::mul_down (lower_x2k [k - 1],
00125 lower_x2);
00126 lower_x2k [k] = rnd::div_down (lower_x2k [k],
00127 factor);
00128 upper_x2k [k] = rnd::mul_up (upper_x2k [k - 1],
00129 upper_x2);
00130 upper_x2k [k] = rnd::div_up (upper_x2k [k],
00131 factor);
00132 }
00133 }
00134
00135 return;
00136 }
00137
00138 template <class NumType, int nTerms>
00139 inline NumType tOpenSine<NumType,nTerms>::lowerBoundTaylor (const NumType &x)
00140 {
00141
00142 typedef tRounding<NumType> rnd;
00143
00144
00145 int n = (nTerms & 1) ? (nTerms + 1) : (nTerms);
00146
00147
00148 NumType lower_x2k [nTerms + 1];
00149 NumType upper_x2k [nTerms + 1];
00150 computeTaylorTerms (x, lower_x2k, upper_x2k, n);
00151
00152
00153 NumType result = 0;
00154 for (int k = n - 1; k >= 0; -- k)
00155 {
00156
00157 if (k & 1)
00158 result = rnd::sub_down (result, upper_x2k [k]);
00159
00160
00161 else
00162 result = rnd::add_down (result, lower_x2k [k]);
00163 }
00164
00165 return result;
00166 }
00167
00168 template <class NumType, int nTerms>
00169 inline NumType tOpenSine<NumType,nTerms>::upperBoundTaylor (const NumType &x)
00170 {
00171
00172 typedef tRounding<NumType> rnd;
00173
00174
00175 int n = (nTerms & 1) ? (nTerms) : (nTerms + 1);
00176
00177
00178 NumType lower_x2k [nTerms + 1];
00179 NumType upper_x2k [nTerms + 1];
00180 computeTaylorTerms (x, lower_x2k, upper_x2k, n);
00181
00182
00183 NumType result = 0;
00184 for (int k = n - 1; k >= 0; -- k)
00185 {
00186
00187 if (k & 1)
00188 result = rnd::sub_up (result, lower_x2k [k]);
00189
00190
00191 else
00192 result = rnd::add_up (result, upper_x2k [k]);
00193 }
00194
00195 return result;
00196 }
00197
00198
00199
00200 template <class NumType, int nTerms>
00201 inline int tOpenSine<NumType,nTerms>::compute
00202 (const NumType &xLeft, const NumType &xRight,
00203 NumType &yLeft, NumType &yRight)
00204 {
00205
00206 typedef tRounding<NumType> rnd;
00207 typedef tNumberPi<NumType> pi;
00208
00209
00210 NumType lower2pi = pi::lowerBound () * 2;
00211 NumType upper2pi = pi::upperBound () * 2;
00212
00213
00214 if (xLeft < 0)
00215 {
00216 int periods = static_cast<int> ((-xLeft) / upper2pi) + 1;
00217 NumType shiftMin = rnd::mul_down (periods, lower2pi);
00218 NumType shiftMax = rnd::mul_up (periods, upper2pi);
00219 NumType newLeft = rnd::add_down (xLeft, shiftMin);
00220 NumType newRight = rnd::add_up (xRight, shiftMax);
00221 while (newLeft < 0)
00222 {
00223
00224 newLeft = rnd::add_down (newLeft, lower2pi);
00225 newRight = rnd::add_up (newRight, upper2pi);
00226 }
00227 while (newLeft > lower2pi)
00228 {
00229
00230 newLeft = rnd::sub_down (newLeft, lower2pi);
00231 newRight = rnd::sub_up (newRight, upper2pi);
00232 }
00233 return shifted2pi (newLeft, newRight, yLeft, yRight);
00234 }
00235 else if (xLeft > upper2pi)
00236 {
00237 int periods = static_cast<int> (xLeft / upper2pi);
00238 NumType shiftMin = rnd::mul_down (periods, lower2pi);
00239 NumType shiftMax = rnd::mul_up (periods, upper2pi);
00240 NumType newLeft = rnd::sub_down (xLeft, shiftMax);
00241 NumType newRight = rnd::sub_up (xRight, shiftMin);
00242 while (newLeft > upper2pi)
00243 {
00244
00245 newLeft = rnd::sub_down (newLeft, upper2pi);
00246 newRight = rnd::sub_up (newRight, lower2pi);
00247 }
00248 return shifted2pi (newLeft, newRight, yLeft, yRight);
00249 }
00250 else
00251 {
00252 return shifted2pi (xLeft, xRight, yLeft, yRight);
00253 }
00254 }
00255
00256 template <class NumType, int nTerms>
00257 inline int tOpenSine<NumType,nTerms>::shifted1pi
00258 (const NumType &xLeft, const NumType &xRight,
00259 NumType &yLeft, NumType &yRight)
00260 {
00261
00262 typedef tRounding<NumType> rnd;
00263 typedef tNumberPi<NumType> pi;
00264
00265
00266 const NumType lowerPi = pi::lowerBound ();
00267 const NumType upperPi = pi::upperBound ();
00268
00269
00270 const NumType lower2pi = lowerPi * 2;
00271 const NumType upper2pi = upperPi * 2;
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 const NumType lowerPi2 = lowerPi / 2;
00283 const NumType upperPi2 = upperPi / 2;
00284
00285
00286 if (xRight <= upperPi2)
00287 {
00288 yLeft = lowerBoundTaylor (xLeft);
00289 yRight = upperBoundTaylor (xRight);
00290 return 0;
00291 }
00292
00293
00294 NumType upper3pi2 = rnd::add_up (upperPi, upperPi2);
00295
00296
00297
00298 if (xLeft <= upperPi2)
00299 {
00300
00301 if (xRight <= upperPi)
00302 {
00303 if (rnd::sub_up (upperPi2, xLeft) <=
00304 rnd::sub_down (xRight, upperPi2))
00305 {
00306 yLeft = lowerBoundTaylor (xRight);
00307 }
00308 else if (rnd::sub_down (lowerPi2, xLeft) >=
00309 rnd::sub_up (xRight, lowerPi2))
00310 {
00311 yLeft = lowerBoundTaylor (xLeft);
00312 }
00313 else
00314 {
00315 NumType leftVal = lowerBoundTaylor (xLeft);
00316 NumType rightVal = lowerBoundTaylor (xRight);
00317 yLeft = (leftVal < rightVal) ?
00318 leftVal : rightVal;
00319 }
00320 yRight = rnd::add_up (1, rnd::min_number ());
00321 return 0;
00322 }
00323
00324
00325 if (xRight <= upper3pi2)
00326 {
00327 yLeft = -upperBoundTaylor
00328 (rnd::sub_up (xRight, lowerPi));
00329 yRight = rnd::add_up (1, rnd::min_number ());
00330 return 0;
00331 }
00332
00333
00334 yLeft = rnd::sub_down (-1, rnd::min_number ());
00335 yRight = rnd::add_up (1, rnd::min_number ());
00336 return 0;
00337 }
00338
00339
00340
00341 {
00342
00343 if (xRight <= upperPi)
00344 {
00345 yLeft = lowerBoundTaylor (xRight);
00346 yRight = upperBoundTaylor (xLeft);
00347 return 0;
00348 }
00349
00350
00351 if (xRight <= upper3pi2)
00352 {
00353 yLeft = -upperBoundTaylor
00354 (rnd::sub_up (xRight, lowerPi));
00355 yRight = upperBoundTaylor (xLeft);
00356 return 0;
00357 }
00358
00359
00360 if (xRight <= upper2pi)
00361 {
00362 yLeft = rnd::sub_down (-1, rnd::min_number ());
00363 yRight = upperBoundTaylor (xLeft);
00364 return 0;
00365 }
00366
00367
00368 if (xRight <= rnd::add_up (upper2pi, upperPi2))
00369 {
00370 if (rnd::sub_up (upperPi, xLeft) <=
00371 rnd::sub_down (xRight, upper2pi))
00372 {
00373 yRight = upperBoundTaylor
00374 (rnd::sub_up (xRight, lower2pi));
00375 }
00376 else if (rnd::sub_down (lowerPi, xLeft) >=
00377 rnd::sub_up (xRight, lower2pi))
00378 {
00379 yRight = upperBoundTaylor (xLeft);
00380 }
00381 else
00382 {
00383 NumType leftVal = upperBoundTaylor (xLeft);
00384 NumType rightVal = upperBoundTaylor
00385 (rnd::sub_up (xRight, lower2pi));
00386 yRight = (leftVal < rightVal) ?
00387 rightVal : leftVal;
00388 }
00389 yLeft = rnd::sub_down (-1, rnd::min_number ());
00390 return 0;
00391 }
00392
00393
00394 yLeft = rnd::sub_down (-1, rnd::min_number ());
00395 yRight = rnd::add_up (1, rnd::min_number ());
00396 return 0;
00397 }
00398 }
00399
00400 template <class NumType, int nTerms>
00401 inline int tOpenSine<NumType,nTerms>::shifted2pi
00402 (const NumType &xLeft, const NumType &xRight,
00403 NumType &yLeft, NumType &yRight)
00404 {
00405
00406 typedef tRounding<NumType> rnd;
00407 typedef tNumberPi<NumType> pi;
00408
00409
00410 if (xLeft <= pi::upperBound ())
00411 return shifted1pi (xLeft, xRight, yLeft, yRight);
00412
00413
00414
00415 shifted1pi (rnd::sub_down (xLeft, pi::upperBound ()),
00416 rnd::sub_up (xRight, pi::upperBound ()),
00417 yRight, yLeft);
00418
00419
00420 yLeft = -yLeft;
00421 yRight = -yRight;
00422 return 0;
00423 }
00424
00425
00426 #endif // _FINRESDYN_OPENSINE_H_
00427