complex.cpp

00001 /*
00002 **  CXSC is a C++ library for eXtended Scientific Computing (V 2.5.1)
00003 **
00004 **  Copyright (C) 1990-2000 Institut fuer Angewandte Mathematik,
00005 **                          Universitaet Karlsruhe, Germany
00006 **            (C) 2000-2011 Wiss. Rechnen/Softwaretechnologie
00007 **                          Universitaet Wuppertal, Germany   
00008 **
00009 **  This library is free software; you can redistribute it and/or
00010 **  modify it under the terms of the GNU Library General Public
00011 **  License as published by the Free Software Foundation; either
00012 **  version 2 of the License, or (at your option) any later version.
00013 **
00014 **  This library is distributed in the hope that it will be useful,
00015 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 **  Library General Public License for more details.
00018 **
00019 **  You should have received a copy of the GNU Library General Public
00020 **  License along with this library; if not, write to the Free
00021 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 /* CVS $Id: complex.cpp,v 1.24 2011/06/07 15:17:38 cxsc Exp $ */
00025 /* New versions of product(...), quotient(...); Blomquist, 26.10.02; */
00026 
00027 #include "complex.hpp"
00028 #include "dot.hpp"
00029 #include "cdot.hpp"
00030 #include "real.hpp"
00031 #include "rmath.hpp"
00032 #include "idot.hpp"
00033 #include "interval.hpp"
00034 
00035 #include "cinterval.hpp"
00036 
00037 namespace cxsc {
00038 
00039 complex::complex(const cdotprecision & a) throw()
00040 {
00041    *this=rnd(a);
00042 }
00043 
00044 complex & complex::operator =(const cdotprecision & a) throw()
00045 {
00046    return *this=rnd(a);
00047 }
00048 
00049 bool operator== (const complex & a, const dotprecision & b)    throw() { return !a.im && a.re==b; }
00050 bool operator== (const dotprecision & a, const complex & b)    throw() { return !b.im && a==b.re; }
00051 bool operator!= (const complex & a, const dotprecision & b)    throw() { return !!a.im || a.re!=b; }
00052 bool operator!= (const dotprecision & a, const complex & b)    throw() { return !!b.im || a!=b.re; }
00053 
00054 complex operator *(const complex &a,const complex &b) throw()
00055 {
00056    complex tmp;
00057    dotprecision dot(0.0);
00058     
00059    accumulate (dot,  a.re, b.re);
00060    accumulate (dot, -a.im, b.im);
00061    rnd (dot, tmp.re, RND_NEXT);
00062 
00063    dot = 0.0;
00064    accumulate (dot, a.re, b.im);
00065    accumulate (dot, a.im, b.re);
00066    rnd (dot, tmp.im, RND_NEXT);
00067 
00068    return tmp;
00069 }
00070 
00071 complex muld(const complex &a, const complex &b) throw()
00072 {  // Blomquist 07.11.02;
00073    complex tmp;
00074    dotprecision dot(0.0);
00075     
00076    accumulate (dot,  a.re, b.re);
00077    accumulate (dot, -a.im, b.im);
00078    rnd (dot, tmp.re, RND_DOWN);
00079 
00080    dot = 0.0;
00081    accumulate (dot, a.re, b.im);
00082    accumulate (dot, a.im, b.re);
00083    rnd (dot, tmp.im, RND_DOWN);
00084 
00085    return tmp;
00086 }
00087 
00088 complex mulu(const complex &a, const complex &b) throw()
00089 {  // Blomquist 07.11.02;
00090    complex tmp;
00091    dotprecision dot(0.0);
00092     
00093    accumulate (dot,  a.re, b.re);
00094    accumulate (dot, -a.im, b.im);
00095    rnd (dot, tmp.re, RND_UP);
00096 
00097    dot = 0.0;
00098    accumulate (dot, a.re, b.im);
00099    accumulate (dot, a.im, b.re);
00100    rnd (dot, tmp.im, RND_UP);
00101 
00102    return tmp;
00103 }
00104 
00105 
00106 static const int Min_Exp_ = 1074, minexpom = -914, 
00107                  maxexpo1 = 1022, MANT_W   = 52;
00108 
00109 void product(real a, real b, real c, real d,
00110              int& overfl, real& p1, interval& p2)
00111 // New version of function product(...) from Blomquist, 26.10.02;
00112 // Input data: a,b,c,d;  Output data: overfl, p1, p2;
00113 // In case of overfl=0 the interval p1+p2 is an inclusion of a*b + c*d;
00114 // overfl=1 (overflow) signalizes that p1+p2 must be multiplied with 2^1074
00115 // to be an inclusion of a*b + c*d;
00116 // overfl=-1 (underflow) signalizes that p1+p2 must be multiplied with 
00117 // 2^-1074 to be an inclusion of a*b + c*d; 
00118 
00119 {  
00120    int exa, exb, exc, exd;  // Exp. von a-d
00121    dotprecision dot;
00122    int inexact;
00123 
00124    overfl  = 0;
00125    inexact = 0; // false
00126 
00127    dot = 0.0;
00128    exa = expo(a);
00129    exb = expo(b);
00130    exc = expo(c);
00131    exd = expo(d);
00132 
00133    if ( sign(a) == 0  ||   sign(b) == 0 )    //  a * b == 0.0
00134       if ( sign(c) == 0  ||  sign(d) == 0 )  //  a * b == c * d == 0
00135                                              //  dot := #(0);
00136          ;    // No Operation necessary
00137       else 
00138       {
00139          //  a * b == 0;  c * d != 0;
00140          if (exc+exd > maxexpo1) 
00141          {
00142             //  overflow !
00143              if ( exc > exd ) c = comp( mant(c), exc-Min_Exp_ );
00144              else d = comp( mant(d), exd-Min_Exp_ );
00145              overfl = 1;
00146          } else 
00147          if  ( exc+exd < minexpom ) 
00148          { // undeflow; 
00149            // c = comp( mant(c), exc+Min_Exp_ ); kann Overflow erzeugen!
00150              if (exc < exd) c = comp( mant(c), exc+Min_Exp_ );
00151              else d = comp( mant(d), exd+Min_Exp_ );
00152              overfl = -1;
00153          }
00154          accumulate(dot,c,d);
00155       } else //  a,b != 0
00156       if ( sign(c) == 0  ||  sign(d) == 0 ) 
00157       {
00158          //  a*b != 0, c * d == 0
00159          if (exa+exb > maxexpo1) 
00160          {
00161             //  overflow !
00162             if ( exa > exb ) a = comp( mant(a), exa-Min_Exp_ );
00163             else b = comp( mant(b), exb-Min_Exp_ );
00164             overfl = 1;
00165          } else 
00166          if (exa+exb < minexpom) 
00167          { // undeflow; 
00168            // a = comp( mant(a), exa+Min_Exp_ ); kann Overflow erzeugen!
00169              if (exa < exb) a = comp( mant(a), exa+Min_Exp_ );
00170              else b = comp( mant(b), exb+Min_Exp_ );
00171             overfl = -1;
00172          }
00173          accumulate(dot,a,b);
00174       } else 
00175       {
00176          // a,b,c,d != 0
00177          if (exa+exb > maxexpo1) 
00178          {  //  overflow bei a*b
00179             if ( exa > exb ) a = comp( mant(a), exa-Min_Exp_ );
00180             else b = comp( mant(b), exb-Min_Exp_ );
00181             if (exc > MANT_W) c = comp( mant(c), exc-Min_Exp_ );
00182             else if (exd > MANT_W)
00183                d = comp( mant(d), exd-Min_Exp_ );
00184             else 
00185             {
00186                // underflow wegen Skalierung bei c*d
00187                 c = 0.0;
00188                 inexact = 1; // true
00189             }
00190             overfl = 1;  // Hat vorher gefehlt!! Blomquist, 24.10.02;
00191          } else if (exc+exd > maxexpo1) 
00192          {
00193             // overflow bei c*d
00194             if ( exc > exd ) c = comp( mant(c), exc-Min_Exp_ );
00195             else d = comp( mant(d), exd-Min_Exp_ );
00196             if (exa > MANT_W) a = comp( mant(a), exa-Min_Exp_ );
00197             else if (exb > MANT_W)
00198                b = comp( mant(b), exb-Min_Exp_ );
00199             else 
00200             {
00201                // underflow wegen Skalierung bei a*b
00202                a = 0.0;
00203                inexact = 1; // true
00204             }
00205             overfl = 1;
00206          } else 
00207          if ( exa+exb < minexpom  &&  exc+exd < minexpom ) 
00208          {
00209             //  underflow bei a*b und bei c*d
00210              if (exa < exb) a = comp( mant(a), exa+Min_Exp_ );
00211              else b = comp( mant(b), exb+Min_Exp_ );
00212              if (exc < exd) c = comp( mant(c), exc+Min_Exp_ );
00213              else d = comp( mant(d), exd+Min_Exp_ );
00214              overfl = -1;
00215          }
00216          accumulate(dot, a, b);
00217          accumulate(dot, c, d);
00218       }
00219 
00220    p1 = rnd(dot);
00221    dot -= p1;
00222    rnd(dot,p2);  // Blomquist, 07.11.02;
00223 
00224    if (inexact)
00225        p2 = _interval( pred(Inf(p2)), succ(Sup(p2)) );
00226 
00227 } // end product
00228 
00229 real quotient (real z1, interval z2, real n1, 
00230                interval n2, int round, int zoverfl, int noverfl)
00231 // z1+z2 is an inclusion of a numerator.
00232 // n1+n2 is an inclusion of a denominator.
00233 // quotient(...) calculates with q1 an approximation of (z1+z2)/(n1+n2)
00234 // using staggered arithmetic.
00235 // Rounding with round (-1,0,+1) is considered.
00236 // zoverfl and noverfl are considered by scaling back with 2^1074 or 2^-1074
00237 // n1+n2 > 0 is assumed.
00238 {
00239    real q1=0, scale;
00240    interval q2, nh;
00241    idotprecision id;
00242    int vorz, anz_scale, ex = 0;
00243 
00244    vorz = sign(z1); // n1,n2 > 0 is assumed!!
00245                     // so the sign of q1 ist sign of z1.
00246    if ( zoverfl == -1  &&  noverfl == 1 ) 
00247    {
00248       //  result in the undeflow range:
00249       switch (round) 
00250       {
00251          case RND_DOWN:
00252             if (vorz >= 0) 
00253                 q1 = 0.0;
00254             else         
00255                 q1 = -minreal; // Blomquist: MinReal --> minreal;
00256             break;
00257          case RND_NEXT:
00258             q1 = 0.0;
00259             break;
00260          case RND_UP:
00261             if (vorz <= 0) 
00262                 q1 = 0.0;
00263             else         
00264                 q1 = minreal;  // Blomquist: MinReal --> minreal;
00265             break;
00266       } // switch
00267    } else if ( zoverfl==1  &&  noverfl==-1 ) 
00268    {  
00269       //  result in the overflow range:
00270       if (vorz >= 0) q1 = MaxReal+MaxReal;  // Overflow
00271       else q1 = -MaxReal-MaxReal;           // Overflow
00272    } else 
00273    {  
00274       q1 = divd(z1, n1);  // down, to get q2 >= 0
00275       nh = _interval(addd(n1, Inf(n2)),
00276                    addu(n1, Sup(n2)));
00277 
00278       // q2:= ##( z1 - q1*n1 + z2 - q1*n2 );
00279       id = z1;
00280       accumulate(id, -q1, n1);
00281       id += z2;
00282       accumulate(id, -q1, n2);
00283       q2 = rnd(id);
00284 
00285       switch (round) // Considering the rounding before scaling
00286       {
00287          case RND_DOWN:
00288             q1 = adddown(q1, divd(Inf(q2), Sup(nh)));
00289             break;
00290          case RND_NEXT:
00291             q1 = q1 + (Inf(q2)+Sup(q2))*0.5/n1;
00292             break;
00293          case RND_UP:
00294             q1 = addup(q1, divu(Sup(q2), Inf(nh)));
00295             break;
00296       } // switch
00297 
00298 
00299       //  scaling back, if numerator|denominator - over-|underflow :
00300 
00301       //  actuell as follows:
00302       //  q1:= comp( mant(q1), expo(q1) + (zoverfl-noverfl)*1074 );
00303       //  The scaling with 2^1074 must be done in two steps with 2^ex
00304       //  and with the factor scale:
00305 
00306       anz_scale = zoverfl - noverfl; // |anz_scale| <= 1; 
00307       if (anz_scale > 0)
00308       {
00309           scale = comp(0.5, +1024);
00310           ex = MANT_W-1;
00311       }
00312       else if (anz_scale < 0)
00313       {
00314           scale = comp(0.5, -1022);
00315           ex = -MANT_W+1;
00316       }
00317       else scale = 1.0;  // ex = 0 is already initialized for this case 
00318 
00319 
00320       if (ex) times2pown(q1,ex); // EXACT part scaling, if ex != 0.
00321       switch (round) // correct rounding with the second factor scale:
00322       {
00323           case RND_DOWN:
00324               q1 = multdown(q1, scale);
00325               break;
00326           case RND_NEXT:
00327               q1 = q1 * scale;
00328               break;
00329           case RND_UP:
00330               q1 = multup(q1, scale);
00331               break;
00332       }  // switch
00333    }
00334    return q1;
00335 } // end of quotient
00336 
00337 complex _c_division(complex a, complex b, int round) throw(DIV_BY_ZERO)
00338 {
00339     if (0.0 == (sqr(Re(b))+sqr(Im(b)))) {
00340       cxscthrow(DIV_BY_ZERO("complex operator / (const complex&,const complex&)"));
00341     }      
00342     
00343    int zoverflow, noverflow;
00344    real z1, n1;
00345    interval z2, n2;
00346    complex tmp;
00347 
00348    product (Re(b), Re(b), Im(b), Im(b), noverflow, n1, n2);
00349    product (Re(a), Re(b), Im(a), Im(b), zoverflow, z1, z2);
00350    SetRe (tmp, quotient (z1, z2, n1, n2, round, zoverflow, noverflow));
00351    product (Im(a), Re(b), -Re(a), Im(b), zoverflow, z1, z2);
00352    SetIm (tmp, quotient (z1, z2, n1, n2, round, zoverflow, noverflow));
00353    return tmp;
00354 }
00355 
00356 complex divn (const complex & a, const complex & b)  
00357 {  // Blomquist: vorher c_divd(...), 07.11.02;
00358    return _c_division(a, b, RND_NEXT);
00359 }
00360 
00361 complex divd (const complex & a, const complex & b) 
00362 {  // Blomquist: vorher c_divd(...), 07.11.02;
00363    return _c_division(a, b, RND_DOWN);
00364 }
00365 
00366 complex divu (const complex & a, const complex & b)  
00367 {  // Blomquist: vorher c_divu(...), 07.11.02;
00368    return _c_division(a, b, RND_UP);
00369 }
00370 
00371 complex operator / (const complex &a,const complex &b) throw()
00372 {
00373    return divn(a,b);
00374 }
00375 
00376 real abs2(const complex &a) throw()
00377 {
00378    dotprecision dot(0.0);
00379    accumulate(dot,a.re,a.re);
00380    accumulate(dot,a.im,a.im);
00381    return rnd(dot);
00382 }
00383 
00384 real abs (complex z) throw()
00385 {   //  calculation of |z|; Blomquist 06.12.02;
00386     return sqrtx2y2(Re(z),Im(z));
00387 }
00388 
00389 
00390 // ---- Ausgabefunkt. ---------------------------------------
00391 
00392 std::ostream & operator << (std::ostream &s, const complex& a) throw()
00393 {
00394    s << '('          
00395      << a.re << ','  
00396      << a.im       
00397      << ')';
00398    return s;
00399 }
00400 std::string & operator << (std::string &s, const complex &a) throw()
00401 {
00402    s+='(';
00403    s << a.re;
00404    s+=',';
00405    s << a.im; 
00406    s+=')';
00407    return s;
00408 }
00409 
00410 std::istream & operator >> (std::istream &s, complex &a) throw()
00411 {
00412    char c;
00413 
00414    skipeolnflag = inpdotflag = true;
00415    c = skipwhitespacessinglechar (s, '(');
00416    if (inpdotflag) 
00417       s.putback(c);
00418 
00419    s >> a.re;
00420 
00421    skipeolnflag = inpdotflag = true;
00422    c = skipwhitespacessinglechar (s, ',');
00423    if (inpdotflag) s.putback(c);
00424 
00425    s >> a.im >> RestoreOpt;
00426 
00427    if (!waseolnflag) 
00428    {
00429       skipeolnflag = false, inpdotflag = true;
00430       c = skipwhitespaces (s);
00431       if (inpdotflag && c != ')') 
00432          s.putback(c);
00433    }
00434 
00435    /*if (a.re > a.im) {
00436       errmon (ERR_INTERVAL(EMPTY));
00437    } */         
00438    return s;
00439 }
00440 
00441 std::string & operator >> (std::string &s, complex &a) throw()
00442 {
00443    s = skipwhitespacessinglechar (s, '(');
00444    s >> SaveOpt >> RndDown >> a.re;
00445    s = skipwhitespacessinglechar (s, ',');
00446    s >> RndUp >> a.im >> RestoreOpt;
00447    s = skipwhitespaces (s);
00448 
00449    if (s[0] == ')') 
00450       s.erase(0,1);
00451 
00452     /*if (a.re > a.im) {
00453       errmon (ERR_INTERVAL(EMPTY));
00454     } */                         
00455    return s;
00456 }
00457 
00458 void operator >>(const std::string &s,complex &a) throw()
00459 {
00460    std::string r(s);
00461    r>>a;
00462 }
00463 void operator >>(const char *s,complex &a) throw()
00464 {
00465    std::string r(s);
00466    r>>a;
00467 }
00468 
00469 complex exp(const complex& x) throw() { return mid(exp(cinterval(x))); }
00470 complex expm1(const complex& x) throw() { return mid(expm1(cinterval(x))); }
00471 complex exp2(const complex& x) throw() { return mid(exp2(cinterval(x))); }
00472 complex exp10(const complex& x) throw() { return mid(exp10(cinterval(x))); }
00473 complex cos(const complex& x) throw() { return mid(cos(cinterval(x))); }
00474 complex sin(const complex& x) throw() { return mid(sin(cinterval(x))); }
00475 complex cosh(const complex& x) throw() { return mid(cosh(cinterval(x))); }
00476 complex sinh(const complex& x) throw() { return mid(sinh(cinterval(x))); }
00477 
00478 complex tan(const complex& x) throw() { return mid(tan(cinterval(x))); }
00479 complex cot(const complex& x) throw() { return mid(cot(cinterval(x))); }
00480 complex tanh(const complex& x) throw() { return mid(tanh(cinterval(x))); }
00481 complex coth(const complex& x) throw() { return mid(coth(cinterval(x))); }
00482 
00483 real arg(const complex& x) throw() { return mid(arg(cinterval(x))); }
00484 real Arg(const complex& x) throw() { return mid(Arg(cinterval(x))); }
00485 
00486 complex ln(const complex& x) throw() { return mid(ln(cinterval(x))); }
00487 complex lnp1(const complex& x) throw() { return mid(lnp1(cinterval(x))); }
00488 complex log2(const complex& x) throw() { return mid(log2(cinterval(x))); }
00489 complex log10(const complex& x) throw() { return mid(log10(cinterval(x))); }
00490 
00491 complex sqr(const complex& x) throw() { return mid(sqr(cinterval(x))); }
00492 
00493 complex sqrt(const complex& x) throw() { return mid(sqrt(cinterval(x))); }
00494 complex sqrtp1m1(const complex& x) throw() { return mid(sqrtp1m1(cinterval(x))); }
00495 complex sqrt1px2(const complex& x) throw() { return mid(sqrt1px2(cinterval(x))); }
00496 complex sqrtx2m1(const complex& x) throw() { return mid(sqrtx2m1(cinterval(x))); }
00497 complex sqrt1mx2(const complex& x) throw() { return mid(sqrt1mx2(cinterval(x))); }
00498 complex sqrt(const complex& x, int d) throw() 
00499 { return mid(sqrt(cinterval(x),d)); }
00500 
00501 std::list<complex> sqrt_all( const complex& c )
00502 { 
00503         complex z;
00504         z = sqrt(c);
00505                 
00506         std::list<complex> res;
00507         res.push_back(  z );
00508         res.push_back( -z );
00509 
00510         return res;
00511 }       // end sqrt_all
00512 
00513 std::list<complex> sqrt_all( const complex& z, int n )
00514                         //
00515 //  sqrt_all(z,n) computes a list of n values approximating all n-th roots of z
00516                         //
00517 //  For n >=3, computing the optimal approximations is very expensive
00518 //  and thus not considered cost-effective.
00519                         //
00520 //  Hence, the polar form is used to calculate sqrt_all(z,n)
00521                         //
00522 {
00523         std::list<complex> res;
00524 
00525         if( n == 0 )
00526         {
00527                 res.push_back( complex(1,0) );
00528                 return res;
00529         }
00530         else if( n == 1 )
00531         {
00532                 res.push_back(z);
00533                 return res;
00534         }
00535         else if( n == 2 ) return sqrt_all( z );
00536         else
00537         {
00538                 real
00539                                 arg_z = arg( z ), root_abs_z = sqrt( abs( z ), n );
00540 
00541                 for(int k = 0; k < n; k++)
00542                 {
00543                         real arg_k = ( arg_z + 2 * k * mid(Pi_interval) ) / n;
00544 
00545                         res.push_back( complex( root_abs_z * cos( arg_k ),
00546                                                                          root_abs_z * sin( arg_k ) ) );
00547                 }
00548                 return res;
00549         }
00550 }
00551 //-- end sqrt_all -------------------------------------------------------------
00552         
00553 
00554 complex power_fast(const complex& x,int d) throw() 
00555 { return mid(power_fast(cinterval(x),d)); }
00556 complex power(const complex& x,int d) throw() 
00557 { return mid(power(cinterval(x),d)); }
00558 complex pow(const complex& x, const real& r) throw() 
00559 { return mid(pow(cinterval(x),interval(r))); }
00560 complex pow(const complex& x, const complex& y) throw() 
00561 { return mid(pow(cinterval(x),cinterval(y))); }
00562 
00563 complex asin(const complex& x) throw() { return mid(asin(cinterval(x))); }
00564 complex acos(const complex& x) throw() { return mid(acos(cinterval(x))); }
00565 complex asinh(const complex& x) throw() { return mid(asinh(cinterval(x))); }
00566 complex acosh(const complex& x) throw() { return mid(acosh(cinterval(x))); }
00567 complex atan(const complex& x) throw() { return mid(atan(cinterval(x))); }
00568 complex acot(const complex& x) throw() { return mid(acot(cinterval(x))); }
00569 complex atanh(const complex& x) throw() { return mid(atanh(cinterval(x))); }
00570 complex acoth(const complex& x) throw() { return mid(acoth(cinterval(x))); }
00571 
00572 } // namespace cxsc
00573 

Generated on Thu Jun 9 11:20:44 2011 for C-XSC - A C++ Class Library for Extended Scientific Computing by  doxygen 1.4.6