opensine.h

Go to the documentation of this file.
00001 /////////////////////////////////////////////////////////////////////////////
00002 ///
00003 /// @file opensine.h
00004 ///
00005 /// An open-interval version of the sine function.
00006 /// This file contains the definition of the sine function in the interval
00007 /// arithmetic based on open intervals, as opposed to closed intervals.
00008 /// Based on this definition, also the other trigonometric functions
00009 /// can be implemented.
00010 ///
00011 /// @author Pawel Pilarczyk
00012 ///
00013 /////////////////////////////////////////////////////////////////////////////
00014 
00015 // Copyright (C) 2007-2010 by Pawel Pilarczyk.
00016 //
00017 // This file is part of my research program package.  This is free software;
00018 // you can redistribute it and/or modify it under the terms of the GNU
00019 // General Public License as published by the Free Software Foundation;
00020 // either version 2 of the License, or (at your option) any later version.
00021 //
00022 // This software is distributed in the hope that it will be useful,
00023 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00025 // GNU General Public License for more details.
00026 //
00027 // You should have received a copy of the GNU General Public License along
00028 // with this software; see the file "license.txt".  If not, write to the
00029 // Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00030 // MA 02111-1307, USA.
00031 
00032 // Started on December 28, 2008. Last revision: December 30, 2008.
00033 
00034 
00035 #ifndef _FINRESDYN_OPENSINE_H_
00036 #define _FINRESDYN_OPENSINE_H_
00037 
00038 
00039 // include local header files
00040 #include "rounding.h"
00041 #include "numberpi.h"
00042 
00043 
00044 // --------------------------------------------------
00045 // ---- a class that computes the sine function -----
00046 // --------------------------------------------------
00047 
00048 /// Computes the sine function using the expansion
00049 /// into the Taylor series at pi/2.
00050 template <class NumType, int nTerms>
00051 class tOpenSine
00052 {
00053 public:
00054         /// Computes the sine function in the open interval arithmetic.
00055         static int compute (const NumType &xLeft, const NumType &xRight,
00056                 NumType &yLeft, NumType &yRight);
00057 
00058 private:
00059         /// Computes the provided number of terms in the expansion
00060         /// of sin(pi+x) in the Taylor series at pi.
00061         static void computeTaylorTerms (const NumType &x,
00062                 NumType *lower_x2k, NumType *upper_x2k, int n);
00063 
00064         /// Returns a lower bound for the sine function.
00065         /// The argument must be in the interval (0,pi).
00066         static NumType lowerBoundTaylor (const NumType &x);
00067 
00068         /// Returns an upper bound for the sine function.
00069         /// The argument must be in the interval (0,pi).
00070         static NumType upperBoundTaylor (const NumType &x);
00071 
00072         /// Computes the sine function in the open interval arithmetic
00073         /// with the arguments shifted so that xLeft is in [0,pi].
00074         static int shifted1pi (const NumType &xLeft, const NumType &xRight,
00075                 NumType &yLeft, NumType &yRight);
00076 
00077         /// Computes the sine function in the open interval arithmetic
00078         /// with the arguments shifted so that xLeft is in [0,2pi].
00079         static int shifted2pi (const NumType &xLeft, const NumType &xRight,
00080                 NumType &yLeft, NumType &yRight);
00081 
00082 }; /* class tOpenSine */
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         // prepare shortcuts for the rounding mode and the number pi
00091         typedef tRounding<NumType> rnd;
00092         typedef tNumberPi<NumType> pi;
00093 
00094         // prepare a lower bound and an upper bound for x^2
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         // compute the terms, including the factorial, but without the sign,
00107         // for the Taylor expansion as in the following formula:
00108         // \sin (\pi/2 + x) = \sum_{k = 0}^{\infty} (-1)^k x^{2k} / (2k)!
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 } /* computeTaylorTerms */
00137 
00138 template <class NumType, int nTerms>
00139 inline NumType tOpenSine<NumType,nTerms>::lowerBoundTaylor (const NumType &x)
00140 {
00141         // prepare a shortcut for the rounding mode
00142         typedef tRounding<NumType> rnd;
00143 
00144         // determine an even strict upper bound for the number of terms
00145         int n = (nTerms & 1) ? (nTerms + 1) : (nTerms);
00146 
00147         // prepare all the terms to add with factorials included
00148         NumType lower_x2k [nTerms + 1];
00149         NumType upper_x2k [nTerms + 1];
00150         computeTaylorTerms (x, lower_x2k, upper_x2k, n);
00151 
00152         // compute the sum for the given number of terms
00153         NumType result = 0;
00154         for (int k = n - 1; k >= 0; -- k)
00155         {
00156                 // subtract the term if its number is odd
00157                 if (k & 1)
00158                         result = rnd::sub_down (result, upper_x2k [k]);
00159 
00160                 // add the term if its number is even
00161                 else
00162                         result = rnd::add_down (result, lower_x2k [k]);
00163         }
00164 
00165         return result;
00166 } /* lowerBoundTaylor */
00167 
00168 template <class NumType, int nTerms>
00169 inline NumType tOpenSine<NumType,nTerms>::upperBoundTaylor (const NumType &x)
00170 {
00171         // prepare a shortcut for the rounding mode
00172         typedef tRounding<NumType> rnd;
00173 
00174         // determine an odd strict upper bound for the number of terms
00175         int n = (nTerms & 1) ? (nTerms) : (nTerms + 1);
00176 
00177         // prepare all the terms to add with factorials included
00178         NumType lower_x2k [nTerms + 1];
00179         NumType upper_x2k [nTerms + 1];
00180         computeTaylorTerms (x, lower_x2k, upper_x2k, n);
00181 
00182         // compute the sum for the given number of terms
00183         NumType result = 0;
00184         for (int k = n - 1; k >= 0; -- k)
00185         {
00186                 // subtract the term if its number is odd
00187                 if (k & 1)
00188                         result = rnd::sub_up (result, lower_x2k [k]);
00189 
00190                 // add the term if its number is even
00191                 else
00192                         result = rnd::add_up (result, upper_x2k [k]);
00193         }
00194 
00195         return result;
00196 } /* upperBoundTaylor */
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         // prepare shortcuts for the rounding mode and the number pi
00206         typedef tRounding<NumType> rnd;
00207         typedef tNumberPi<NumType> pi;
00208 
00209         // prepare bounds for the number 2pi
00210         NumType lower2pi = pi::lowerBound () * 2;
00211         NumType upper2pi = pi::upperBound () * 2;
00212 
00213         // shift the interval so that the left bound is in [0,2pi]
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                 //      std::cout << "Debug: sine add (" << newLeft << ").\n";
00224                         newLeft = rnd::add_down (newLeft, lower2pi);
00225                         newRight = rnd::add_up (newRight, upper2pi);
00226                 }
00227                 while (newLeft > lower2pi)
00228                 {
00229                 //      std::cout << "Debug: sine sub (" << newLeft << ").\n";
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                 //      std::cout << "Debug: sine+sub (" << newLeft << ").\n";
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 } /* compute */
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         // prepare shortcuts for the rounding mode and the number pi
00262         typedef tRounding<NumType> rnd;
00263         typedef tNumberPi<NumType> pi;
00264 
00265         // prepare bounds for the number pi
00266         const NumType lowerPi = pi::lowerBound ();
00267         const NumType upperPi = pi::upperBound ();
00268 
00269         // prepare bounds for the number 2pi
00270         const NumType lower2pi = lowerPi * 2;
00271         const NumType upper2pi = upperPi * 2;
00272 
00273         // check if the width of the interval exceeds the period of sine
00274 //      if (rnd::sub_up (xRight, xLeft) >= lower2pi)
00275 //      {
00276 //              yLeft = rnd::sub_down (-1, rnd::min_number ());
00277 //              yRight = rnd::add_up (1, rnd::min_number ());
00278 //              return 0;
00279 //      }
00280 
00281         // prepare bounds for the number pi/2
00282         const NumType lowerPi2 = lowerPi / 2;
00283         const NumType upperPi2 = upperPi / 2;
00284 
00285         // if both bounds are to the left from pi/2
00286         if (xRight <= upperPi2)
00287         {
00288                 yLeft = lowerBoundTaylor (xLeft);
00289                 yRight = upperBoundTaylor (xRight);
00290                 return 0;
00291         }
00292 
00293         // prepare bounds for the number 3pi/2
00294         NumType upper3pi2 = rnd::add_up (upperPi, upperPi2);
00295 //      NumType lower3pi2 = rnd::add_down (lowerPi, lowerPi2);
00296 
00297         // if the left bound is below pi/2, but the right bound is larger
00298         if (xLeft <= upperPi2)
00299         {
00300                 // if the right bound is in [pi/2, pi]
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                 // if the right bound is in [pi, 3/2 pi]
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                 // if the right bound is beyond 3/2 pi
00334                 yLeft = rnd::sub_down (-1, rnd::min_number ());
00335                 yRight = rnd::add_up (1, rnd::min_number ());
00336                 return 0;
00337         }
00338 
00339         // if the left bound is between pi/2 and pi
00340 //      if (xLeft <= upperPi)
00341         {
00342                 // if the right bound is also between pi/2 and pi
00343                 if (xRight <= upperPi)
00344                 {
00345                         yLeft = lowerBoundTaylor (xRight);
00346                         yRight = upperBoundTaylor (xLeft);
00347                         return 0;
00348                 }
00349 
00350                 // if the right bound is in [pi, 3/2 pi]
00351                 if (xRight <= upper3pi2)
00352                 {
00353                         yLeft = -upperBoundTaylor
00354                                 (rnd::sub_up (xRight, lowerPi));
00355                         yRight = upperBoundTaylor (xLeft);
00356                         return 0;
00357                 }
00358 
00359                 // if the right bound is in [3/2 pi, 2pi]
00360                 if (xRight <= upper2pi)
00361                 {
00362                         yLeft = rnd::sub_down (-1, rnd::min_number ());
00363                         yRight = upperBoundTaylor (xLeft);
00364                         return 0;
00365                 }
00366 
00367                 // if the right bound is in [2pi, 2pi+pi/2]
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                 // otherwise the full range of values is covered
00394                 yLeft = rnd::sub_down (-1, rnd::min_number ());
00395                 yRight = rnd::add_up (1, rnd::min_number ());
00396                 return 0;
00397         }
00398 } /* shifted1pi */
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         // prepare shortcuts for the rounding mode and the number pi
00406         typedef tRounding<NumType> rnd;
00407         typedef tNumberPi<NumType> pi;
00408 
00409         // if the left endpoint is below pi then fine
00410         if (xLeft <= pi::upperBound ())
00411                 return shifted1pi (xLeft, xRight, yLeft, yRight);
00412 
00413         // compute the function with the arguments shifted by pi
00414         // (note the reversed order of results as they will be negated)
00415         shifted1pi (rnd::sub_down (xLeft, pi::upperBound ()),
00416                 rnd::sub_up (xRight, pi::upperBound ()),
00417                 yRight, yLeft);
00418 
00419         // flip the resulting interval and finish
00420         yLeft = -yLeft;
00421         yRight = -yRight;
00422         return 0;
00423 } /* shifted2pi */
00424 
00425 
00426 #endif // _FINRESDYN_OPENSINE_H_
00427 

Generated on Mon Apr 12 15:09:57 2010 for The Finite Resolution Dynamics Software by  doxygen 1.5.3