real sqrtx2y2(const real& x, const real& y) throw() // calculating sqrt(x^2 + y^2) in high accuracy. Blomquist 01.12.02 { real a,b,r; dotprecision dot; int exa,exb,ex; a = x; b = y; exa = expo(a); exb = expo(b); if (exb > exa) { // Permutation of a,b: r = a; a = b; b = r; ex = exa; exa = exb; exb = ex; } // |a| >= |b| // a = |a| >= |b| > 0: ex = 511 - exa; // scaling a with 2^ex --> expo(a) == 511, --> a*a and times2pown(a,ex); // b*b without overflow. An underflow of b*b will not times2pown(b,ex); // affect the accuracy of the result! dot = 0; accumulate(dot,a,a); accumulate(dot,b,b); r = rnd(dot); r = sqrt(r); // sqrt(...) declared in rmath.hpp times2pown(r,-ex); // back-scaling return r; } // sqrtx2y2
void sqr2uv(const real& x, real& u, real& v) // Liefert u,v für: x2 = u + v; EXAKTE Darstellung, falls kein overflow // auftritt und v im normalisierten Bereich liegt. u > |v| // Vorsicht: Funktioniert zunächst nur auf INTEL-Systemen!!! { real a,b,t,y1,y2; a = Cut26(x); b = x-a; // x = a+b; u = x*x; t = u - a*a; // exakte Auswertung! y2 = a*b; times2pown(y2,1); // y2 = 2*a*b, exakt! t -= y2; // Jetzt fehlt noch: t2 - b*b, aber b*b wird nicht immer korrekt berechnet, // daher nochmalige Aufspaltung von b in y1+y2!! y1 = Cut25(b); y2 = b - y1; // b = y1+y2, exakt; t -= y1*y1; if (sign(y2)!=0) { a = y1*y2; times2pown(a,1); // a = 2*y1*y2, exakt! t -= a; t -= y2*y2; } v = -t; } // sqr2uv
real sqrt1mx2(const real& x) throw(STD_FKT_OUT_OF_DEF) // sqrt(1-x2); rel. Fehlerschranke: eps = 3.700747E-16 = e(f) // Blomquist, 19.06.04; { real t=x,res; int ex; if (sign(t)<0) t = -t; // Argument t >=0; if (t>1) cxscthrow(STD_FKT_OUT_OF_DEF("real sqrt1mx2(const real&)")); // For argument t now it holds: 0 <= t <=1; ex = expo(t); if (ex<=-26) res = 1; // t < 2^(-26) --> res = 1 else if (ex<=-15) { // t < 2^(-15) --> res = 1-x2/2 res = t*t; times2pown(res,-1); res = 1 - res; } else { if (ex>=0) { // ex>=0 --> t>=0.5; res = 1-t; // res: delta = 1-t; t = res * res; times2pown(res,1); // res: 2*delta res = res - t; // res: 1-x2 = 2*delta - delta2 } else res = 1-t*t; // res: Maschinenwert von 1-x2 res = sqrt(res); // res: Nullte Naeherung } return res; } // sqrt1mx2
real expmx2(const real& x) throw() // e^(-x^2); rel. Fehlerschranke: eps = 4.618919E-16 = e(f) gilt // fuer alle |x| <= expmx2_x0 = 26.61571750925.... // Fuer |x| > expmx2_x0 --> expmx2(x) = 0; // Blomquist, 05.07.04; { real t=x,u,v,res=0; int ex; if (t<0) t = -t; // t >= 0; ex = expo(t); if (ex<=-26) res = 1; // t < 2^(-26) else if (ex<=-6) // t < 2^(-6) { u = t*t; v = u; times2pown(v,-1); // v: 0.5*x2 res = 1-u*( 1-v*(1-u/3) ); } else if (t<=expmx2_x0) { sqr2uv(x,u,v); // u:= x*x,v aus S(2,53); x2 = u+v (exakt!) res = exp(-u); if (v!=0) { times2pown(res,500); // Die Skalierung verhindert, dass v *= res; // v*exp(-u) in den denormalisierten Bereich faellt res -= v; times2pown(res,-500); // Rueckskalierung } } return res; } // expmx2
static void xscalbln(xcomplex *z, long int a) { cxsc::real re = Re(*z), im = Im(*z); times2pown(re,a); times2pown(im,a); *z = cxsc::complex(re,im); }
real expx2(const real& x) // e^(+x^2); rel. Fehlerschranke: eps = 4.618958E-16 = e(f) gilt // fuer alle |x| <= x0 = 26.64174755704632.... // x0 = 7498985273150791.0 / 281474976710656.0; // Fuer |x| > x0 --> Programmabbruch // Ausfuehrlich getestet; Blomquist, 26.07.06; { real t=x,u,v,res; int ex; if (t<0) t = -t; // t >= 0; ex = expo(t); if (ex<=-26) res = 1; // t < 2^(-26) else if (ex<=-6) // t < 2^(-6) { u = t*t; v = u; times2pown(v,-1); // v: 0.5*x^2 res = 1+u*( 1+v*(1+u/3) ); } else { sqr2uv(x,u,v); // u := x*x und v aus S(2,53); // x^2 = u+v ist exakt! res = exp(u); v *= res; // v*exp(+u) res += v; } return res; } // expx2
real sqrtx2m1(const real& x) // sqrt(x^2-1); rel. Fehlerschranke: eps = 2.221305E-16 = e(f) // Blomquist, 13.04.04; { const real c1 = 1.000732421875, c2 = 44000.0, c3 = 1024.0; // c1,c2,c3 werden exakt gespeichert! real res,ep,ep2,s1,s2,x1,x2,arg=x; if (sign(arg)<0) arg = -arg; // arg = |x| >= 0 if (arg <= c1) { // x = 1+ep; x^2-1 = 2*ep + ep^2; ep = x - 1; // Differenz rundungsfehlerfrei! ep2 = ep*ep; // ep2 i.a. fehlerbehaftet! times2pown(ep,1); // ep = 2*ep; res = sqrt(ep+ep2); // res=y0: Startwert; // x - y0^2 = (2*eps - s1^2) + [eps^2 - s2*(y0 + s1)] s1 = Cut26(res); s2 = res - s1; // Startwert y0 = s1 + s2; arg = ep - s1*s1; // arg = 2*eps - s1^2; arg += (ep2 - s2*(res+s1)); // arg = x - y0^2 if (sign(arg)>0) { arg = arg / res; times2pown(arg,-1); res += arg; // 1. Newton-Schritt beendet; eps = 2.221261E-16 } } else if (arg<c2) { // x-y0^2 = [(x1^2-1)-s1^2] + [x2*(x+x1)-s2*(y0+s1)] x1 = Cut26(arg); x2 = arg - x1; // arg = x = x1 + x2; ep2 = x2*(arg+x1); // ep2 ist fehlerbehaftet x2 = x1*x1; ep = x2-1; res = sqrt(ep+ep2); // res ist Startwert für Newton-Verfahren s1 = Cut26(res); s2 = res - s1; // Startwert = s1 + s2; ep2 = ep2 - s2 * (res+s1); // ep2 = [x2*(x+x1)-s2*(y0+s1)] if (arg<c3) ep -= s1*s1; // ep = (x1^2-1) - s1^2; else { x2 -= s1*s1; // x2 = x1^2-s1^2 ep = x2 - 1; } // ep = (x1^2-s1^2) - 1; ep += ep2; // ep = x - y0^2; ep /= res; times2pown(ep,-1); res = res + ep; // 1. Newton-Schritt in hoher Genauigkeit // beendet; eps = 2.221305E-16 } else { // arg = |x| >= 44000; res = -1/arg; times2pown(res,-1); // Multiplikation mit 0.5; res += arg; // res = x - 1/(2*x); eps = 2.221114E-16 } return res; } // sqrtx2m1 (Punktargumente)
real sqrtp1m1(const real& x) throw() // sqrtp1m1(x) = sqrt(x+1)-1; // Blomquist, 05.08.03; { real y = x; int ex = expo(x); if (ex<=-50) times2pown(y,-1); // |x|<2^(-50); fast division by 2 else if (ex>=105) y = sqrt(x); // x >= 2^(+104) = 2.02824...e+31 else if (ex>=53) y = sqrt(x)-1; // x >= 2^(+52) = 4.50359...e+15 else if (x>-0.5234375 && x<=sqrtp1m1_s ) y = x / (sqrt(x+1) + 1); else y = sqrt(x+1)-1; return y; }
real expx2m1(const real& x) // e^(+x^2)-1; rel. Fehlerschranke: eps = 4.813220E-16 = e(f) gilt // fuer alle x, mit: 2^(-511) <= x <= x0 = 26.64174755704632.... // x0 = 7498985273150791.0 / 281474976710656.0; // Fuer x > x0 --> Programmabbruch wegen Overflow; // Fuer 0 < x < 2^(-511) --> Programmabbruch, denorm. Bereich!! // Ausfuehrlich getestet; Blomquist, 10.08.2006; { real t(x),u,v,y,res(0); int ex; if (t<0) t = -t; // t >= 0; if (t>=6.5) res = expx2(t); else { ex = expo(t); sqr2uv(x,u,v); // u := x*x und v aus S(2,53); if (ex>=2) // g4(x) { y = exp(u); res = 1 - v*y; res = y - res; } else if (ex>=-8) res = expm1(u) + v*exp(u); // g3(x) else if (ex>=-25) { // g2(x) y = u*u; times2pown(y,-1); res = (1+u/3)*y + u; } else if(ex>=-510) res = u; // g1(x) else if (ex>=-1073) { std::cerr << "expx2m1: denormalized range!" << std::endl; exit(1); } } return res; } // expx2m1
real ln_sqrtx2y2(const real& x, const real& y) throw(STD_FKT_OUT_OF_DEF) // ln( sqrt(x^2+y^2) ) == 0.5*ln(x^2+y^2); Blomquist, 21.11.03; // Relative error bound: 5.160563E-016; // Absolute error bound: 2.225075E-308; if x=1 and 0<=y<=b0; { int j,N; real a,b,r,r1; dotprecision dot; a = sign(x)<0 ? -x : x; // a = |x| >= 0; b = sign(y)<0 ? -y : y; // b = |y| >= 0; int exa=expo(a), exb=expo(b), ex; if (b > a) { r = a; a = b; b = r; ex = exa; exa = exb; exb = ex; } // It holds now: 0 <= b <= a if (sign(a)==0) cxscthrow(STD_FKT_OUT_OF_DEF ("real ln_sqrtx2y2(const real&, const real&)")); if (exa>20) // to avoid overflow by calculating a^2 + b^2 { // a>=2^(20): j = Interval_Nr(B_lnx2y2_1,21,exa); // j: No. of subinterval N = B_lnx2y2_N1[j]; // N: Optimal int value if (exb-exa > -25) { // For (exb-exa>-25) we use the complete term: // N*ln(2) + [ln(2^(-N)*a)+0.5*ln(1+(b/a)^2)] b = b/a; // a > 0 b = lnp1(b*b); times2pown(b,-1); // exact division by 2 times2pown(a,-N); r = b + ln(a); // [ ... ] calculated! r += B_lnx2y2_c1[j]; } else { // For (exb-exa<=-25) only two summands!: times2pown(a,-N); r = ln(a) + B_lnx2y2_c1[j]; } } else // exa<=20 or a<2^(20): { // Now calculation of a^2+b^2 without overflow: if (exa<=-20) // to avoid underflow by calculating a^2+b^2 if (exa<=-1022) // a in the denormalized range { r = b/a; r = lnp1(r*r); times2pown(r,-1); // r: 0.5*ln(1+..) times2pown(a,1067); r += ln(a); // [ .... ] ready r -= ln2_1067; // rel. error = 2.459639e-16; } else // MinReal=2^(-1022) <= a < 2^(-20) { // Calculating the number j of the subinterval: j = 20 - Interval_Nr(B_lnx2y2_2,21,exa); r = a; times2pown(r,B_lnx2y2_N1[j]); r = ln(r); // r: ln(2^N*a); if (exb-exa > -25) { // calculating the complete term b = b/a; a = lnp1(b*b); times2pown(a,-1); r += a; // [ ... ] ready now } // We now have: exb-exa<=-25, ==> b/a <= 2^(-24); r -= B_lnx2y2_c1[j]; // 0.5*ln(1+(b/a)^2) neglected! // relative error = 4.524090e-16 in both cases; } else // calculation of a^2+b^2 without overflow or underflow: { // exa>-20 respective a>=2^(-20): dot = 0; accumulate(dot,a,a); accumulate(dot,b,b); // dot = a^2+b^2, exact! real s = rnd(dot); // s = a^2 + b^2, rounded! if (s>=0.25 && s<=1.75) if (s>=0.828125 && s<=1.171875) { // Series: if (a==1 && exb<=-28) { r = b; times2pown(r,-1); r *= b; } else { dot -= 1; r = rnd(dot); // r = a^2+b^2-1 rounded! r = lnp1(r); times2pown(r,-1); } } else { // Reading dot = a^2+b^2 twice: r = rnd(dot); dot -= r; r1 = rnd(dot); // a^2+b^2 = r+r1, rounded! r1 = lnp1(r1/r); r = ln(r) + r1; times2pown(r,-1); // exact division by 2 } else { // calculating straight from: 0.5*ln(x^2+y^2) r = ln(s); times2pown(r,-1); } } } return r; } // ln_sqrtx2y2