/* GSL - Generic Sound Layer * Copyright (C) 2001 Stefan Westerfeld and Tim Janik * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "gslmath.h" #include #include #define RING_BUFFER_LENGTH (16) #define PRINTF_DIGITS "1270" #define FLOAT_STRING_SIZE (2048) /* factorization constants: 2^(1/12), ln(2^(1/12)) and 2^(1/(12*6)) * retrived with: #include #include typedef long double ld; int main (void) { ld r, l; cout.precision(256); r = pow ((ld) 2, (ld) 1 / (ld) 12); cout << "2^(1/12) =\n"; cout << "2^" << (ld) 1 / (ld) 12 << " =\n"; cout << r << "\n"; l = log (r); cout << "ln(2^(1/12)) =\n"; cout << "ln(" << r << ") =\n"; cout << l << "\n"; r = pow ((ld) 2, (ld) 1 / (ld) 72); cout << "2^(1/72) =\n"; cout << "2^" << (ld) 1 / (ld) 72 << " =\n"; cout << r << "\n"; return 0; } */ /* --- prototypes --- */ static void zrhqr (double a[], int m, double rtr[], double rti[]); static double rf (double x, double y, double z); static double ellf (double phi, double ak); static void sncndn (double uu, double emmc, double *sn_p, double *cn_p, double *dn_p); static void sncndnC (GslComplex uu, GslComplex emmc, GslComplex *sn_p, GslComplex *cn_p, GslComplex *dn_p); static GslComplex rfC (GslComplex x, GslComplex y, GslComplex z); /* --- functions --- */ static inline char* pretty_print_double (char *str, double d) { char *s= str; sprintf (s, "%."PRINTF_DIGITS"f", d); while (*s) s++; while (s[-1] == '0' && s[-2] != '.') s--; *s = 0; return s; } char* gsl_complex_list (unsigned int n_points, GslComplex *points, const char *indent) { static unsigned int rbi = 0; static char* rbuffer[RING_BUFFER_LENGTH] = { NULL, }; char *s, *tbuffer = g_newa (char, (FLOAT_STRING_SIZE * 2 * n_points)); unsigned int i; rbi++; if (rbi >= RING_BUFFER_LENGTH) rbi -= RING_BUFFER_LENGTH; if (rbuffer[rbi] != NULL) g_free (rbuffer[rbi]); s = tbuffer; for (i = 0; i < n_points; i++) { *s = 0; if (indent) strcat (s, indent); while (*s) s++; s = pretty_print_double (s, points[i].re); *s++ = ' '; s = pretty_print_double (s, points[i].im); *s++ = '\n'; } *s++ = 0; rbuffer[rbi] = g_strdup (tbuffer); return rbuffer[rbi]; } char* gsl_complex_str (GslComplex c) { static unsigned int rbi = 0; static char* rbuffer[RING_BUFFER_LENGTH] = { NULL, }; char *s, tbuffer[FLOAT_STRING_SIZE * 2]; rbi++; if (rbi >= RING_BUFFER_LENGTH) rbi -= RING_BUFFER_LENGTH; if (rbuffer[rbi] != NULL) g_free (rbuffer[rbi]); s = tbuffer; *s++ = '{'; s = pretty_print_double (s, c.re); *s++ = ','; *s++ = ' '; s = pretty_print_double (s, c.im); *s++ = '}'; *s++ = 0; rbuffer[rbi] = g_strdup (tbuffer); return rbuffer[rbi]; } char* gsl_poly_str (unsigned int degree, double *a, const char *var) { static unsigned int rbi = 0; static char* rbuffer[RING_BUFFER_LENGTH] = { NULL, }; char *s, *tbuffer = g_newa (char, degree * FLOAT_STRING_SIZE); unsigned int i; if (!var) var = "x"; rbi++; if (rbi >= RING_BUFFER_LENGTH) rbi -= RING_BUFFER_LENGTH; if (rbuffer[rbi] != NULL) g_free (rbuffer[rbi]); s = tbuffer; *s++ = '('; s = pretty_print_double (s, a[0]); for (i = 1; i <= degree; i++) { *s++ = '+'; *s = 0; strcat (s, var); while (*s) s++; *s++ = '*'; *s++ = '('; s = pretty_print_double (s, a[i]); } while (i--) *s++ = ')'; *s++ = 0; rbuffer[rbi] = g_strdup (tbuffer); return rbuffer[rbi]; } char* gsl_poly_str1 (unsigned int degree, double *a, const char *var) { static unsigned int rbi = 0; static char* rbuffer[RING_BUFFER_LENGTH] = { NULL, }; char *s, *tbuffer = g_newa (char, degree * FLOAT_STRING_SIZE); unsigned int i, need_plus = 0; if (!var) var = "x"; rbi++; if (rbi >= RING_BUFFER_LENGTH) rbi -= RING_BUFFER_LENGTH; if (rbuffer[rbi] != NULL) g_free (rbuffer[rbi]); s = tbuffer; *s++ = '('; if (a[0] != 0.0) { s = pretty_print_double (s, a[0]); need_plus = 1; } for (i = 1; i <= degree; i++) { if (a[i] == 0.0) continue; if (need_plus) { *s++ = ' '; *s++ = '+'; *s++ = ' '; } if (a[i] != 1.0) { s = pretty_print_double (s, a[i]); *s++ = '*'; } *s = 0; strcat (s, var); while (*s) s++; if (i > 1) { *s++ = '*'; *s++ = '*'; sprintf (s, "%u", i); while (*s) s++; } need_plus = 1; } *s++ = ')'; *s++ = 0; rbuffer[rbi] = g_strdup (tbuffer); return rbuffer[rbi]; } void gsl_complex_gnuplot (const char *file_name, unsigned int n_points, GslComplex *points) { FILE *fout = fopen (file_name, "w"); fputs (gsl_complex_list (n_points, points, ""), fout); fclose (fout); } double gsl_temp_freq (double kammer_freq, int halftone_delta) { double factor; factor = pow (GSL_2_POW_1_DIV_12, halftone_delta); return kammer_freq * factor; } void gsl_poly_from_re_roots (unsigned int degree, double *a, GslComplex *roots) { unsigned int i; /* initialize polynomial */ a[1] = 1; a[0] = -roots[0].re; /* monomial factor multiplication */ for (i = 1; i < degree; i++) { unsigned int j; a[i + 1] = a[i]; for (j = i; j >= 1; j--) a[j] = a[j - 1] - a[j] * roots[i].re; a[0] *= -roots[i].re; } } void gsl_cpoly_from_roots (unsigned int degree, GslComplex *c, GslComplex *roots) { unsigned int i; /* initialize polynomial */ c[1].re = 1; c[1].im = 0; c[0].re = -roots[0].re; c[0].im = -roots[0].im; /* monomial factor multiplication */ for (i = 1; i < degree; i++) { GslComplex r = gsl_complex (-roots[i].re, -roots[i].im); unsigned int j; c[i + 1] = c[i]; for (j = i; j >= 1; j--) c[j] = gsl_complex_add (c[j - 1], gsl_complex_mul (c[j], r)); c[0] = gsl_complex_mul (c[0], r); } } void gsl_poly_complex_roots (unsigned int degree, double *a, /* [0..degree] (degree+1 elements) */ GslComplex *roots) /* [degree] */ { double *roots_re = g_newa (double, 1 + degree); double *roots_im = g_newa (double, 1 + degree); unsigned int i; zrhqr (a, degree, roots_re, roots_im); for (i = 0; i < degree; i++) { roots[i].re = roots_re[1 + i]; roots[i].im = roots_im[1 + i]; } } double gsl_ellip_rf (double x, double y, double z) { return rf (x, y, z); } double gsl_ellip_F (double phi, double ak) { return ellf (phi, ak); } double gsl_ellip_sn (double u, double emmc) { double sn; sncndn (u, emmc, &sn, NULL, NULL); return sn; } double gsl_ellip_asn (double y, double emmc) { return y * rf (1.0 - y * y, 1.0 - y * y * (1.0 - emmc), 1.0); } GslComplex gsl_complex_ellip_asn (GslComplex y, GslComplex emmc) { return gsl_complex_mul (y, rfC (gsl_complex_sub (gsl_complex (1.0, 0), gsl_complex_mul (y, y)), gsl_complex_sub (gsl_complex (1.0, 0), gsl_complex_mul3 (y, y, gsl_complex_sub (gsl_complex (1.0, 0), emmc))), gsl_complex (1.0, 0))); } GslComplex gsl_complex_ellip_sn (GslComplex u, GslComplex emmc) { GslComplex sn; sncndnC (u, emmc, &sn, NULL, NULL); return sn; } double gsl_bit_depth_epsilon (guint n_bits) { /* epsilon for various bit depths, based on significance of one bit, * minus fudge. created with: * { echo "scale=40"; for i in `seq 1 32` ; do echo "1/2^$i - 10^-($i+1)" ; done } | bc | sed 's/$/,/' */ static const double bit_epsilons[] = { .4900000000000000000000000000000000000000, .2490000000000000000000000000000000000000, .1249000000000000000000000000000000000000, .0624900000000000000000000000000000000000, .0312490000000000000000000000000000000000, .0156249000000000000000000000000000000000, .0078124900000000000000000000000000000000, .0039062490000000000000000000000000000000, .0019531249000000000000000000000000000000, .0009765624900000000000000000000000000000, .0004882812490000000000000000000000000000, .0002441406249000000000000000000000000000, .0001220703124900000000000000000000000000, .0000610351562490000000000000000000000000, .0000305175781249000000000000000000000000, .0000152587890624900000000000000000000000, .0000076293945312490000000000000000000000, .0000038146972656249000000000000000000000, .0000019073486328124900000000000000000000, .0000009536743164062490000000000000000000, .0000004768371582031249000000000000000000, .0000002384185791015624900000000000000000, .0000001192092895507812490000000000000000, .0000000596046447753906249000000000000000, .0000000298023223876953124900000000000000, .0000000149011611938476562490000000000000, .0000000074505805969238281249000000000000, .0000000037252902984619140624900000000000, .0000000018626451492309570312490000000000, .0000000009313225746154785156249000000000, .0000000004656612873077392578124900000000, .0000000002328306436538696289062490000000, }; return bit_epsilons[CLAMP (n_bits, 1, 32) - 1]; } /* --- Numerical Receipes --- */ #define gsl_complex_rmul(scale, c) gsl_complex_scale (c, scale) #define ONE gsl_complex (1.0, 0) #define SIGN(a,b) ((b) >= 0.0 ? fabs (a) : -fabs(a)) static inline int IMAX (int i1, int i2) { return i1 > i2 ? i1 : i2; } static inline double DMIN (double d1, double d2) { return d1 < d2 ? d1 : d2; } static inline double DMAX (double d1, double d2) { return d1 > d2 ? d1 : d2; } static inline double DSQR (double d) { return d == 0.0 ? 0.0 : d * d; } #define nrerror(error) g_error ("NR-ERROR: %s", (error)) static inline double* vector (long nl, long nh) /* allocate a vector with subscript range v[nl..nh] */ { double *v = g_new (double, nh - nl + 1 + 1); return v - nl + 1; } static inline void free_vector (double *v, long nl, long nh) { g_free (v + nl - 1); } static inline double** matrix (long nrl, long nrh, long ncl, long nch) /* allocate a matrix with subscript range m[nrl..nrh][ncl..nch] */ { long i, nrow = nrh - nrl + 1, ncol = nch - ncl + 1; double **m = g_new (double*, nrow + 1); m += 1; m -= nrl; m[nrl] = g_new (double, nrow * ncol + 1); m[nrl] += 1; m[nrl] -= ncl; for (i = nrl + 1; i <= nrh; i++) m[i] = m[i - 1] + ncol; return m; } static inline void free_matrix (double **m, long nrl, long nrh, long ncl, long nch) { g_free (m[nrl] + ncl - 1); g_free (m + nrl - 1); } static void poldiv (double u[], int n, double v[], int nv, double q[], double r[]) /* Given the n+1 coefficients of a polynomial of degree n in u[0..n], and the nv+1 coefficients of another polynomial of degree nv in v[0..nv], divide the polynomial u by the polynomial v ("u"/"v") giving a quotient polynomial whose coefficients are returned in q[0..n], and a remainder polynomial whose coefficients are returned in r[0..n]. The elements r[nv..n] and q[n-nv+1..n] are returned as zero. */ { int k,j; for (j=0;j<=n;j++) { r[j]=u[j]; q[j]=0.0; }for (k=n-nv;k>=0;k--) { q[k]=r[nv+k]/v[nv]; for (j=nv+k-1;j>=k;j--) r[j] -= q[k]*v[j-k]; }for (j=nv;j<=n;j++) r[j]=0.0; } #define MAX_ITER_BASE 9 /* TIMJ: was 3 */ #define MAX_ITER_FAC 20 /* TIMJ: was 10 */ static void hqr (double **a, int n, double wr[], double wi[]) /* Finds all eigenvalues of an upper Hessenberg matrix a[1..n][1..n]. On input a can be exactly as output from elmhes §11.5; on output it is destroyed. The real and imaginary parts of the eigenvalues are returned in wr[1..n] and wi[1..n], respectively. */ { int nn,m,l,k,j,its,i,mmin; double z,y,x,w,v,u,t,s,r,q,p,anorm; r=q=p=0; /* TIMJ: silence compiler */ anorm=0.0; /* Compute matrix norm for possible use in lo- */ for (i=1;i<=n;i++) /* cating single small subdiagonal element. */ for (j=IMAX (i-1,1);j<=n;j++) anorm += fabs (a[i][j]); nn=n; t=0.0; /* Gets changed only by an exceptional shift. */ while (nn >= 1) { /* Begin search for next eigenvalue. */ its=0; do {for (l=nn;l>=2;l--) { /* Begin iteration: look for single small subdi- */ s=fabs (a[l-1][l-1])+fabs (a[l][l]); /* agonal element. */ if (s == 0.0) s=anorm; if ((double)(fabs (a[l][l-1]) + s) == s) break; } x=a[nn][nn]; if (l == nn) { /* One root found. */ wr[nn]=x+t; wi[nn--]=0.0; } else { y=a[nn-1][nn-1]; w=a[nn][nn-1]*a[nn-1][nn]; if (l == (nn-1)) { /* Two roots found... */ p=0.5*(y-x); q=p*p+w; z=sqrt (fabs (q)); x += t; if (q >= 0.0) { /* ...a real pair. */ z=p+SIGN (z,p); wr[nn-1]=wr[nn]=x+z; if (z) wr[nn]=x-w/z; wi[nn-1]=wi[nn]=0.0; } else { /* ...a complex pair. */ wr[nn-1]=wr[nn]=x+p; wi[nn-1]= -(wi[nn]=z); } nn -= 2; } else { /* No roots found. Continue iteration. */ if (its == MAX_ITER_BASE * MAX_ITER_FAC) nrerror ("Too many iterations in hqr"); if (its && !(its%MAX_ITER_FAC)) { /* Form exceptional shift. */ t += x; for (i=1;i<=nn;i++) a[i][i] -= x; s=fabs (a[nn][nn-1])+fabs (a[nn-1][nn-2]); y=x=0.75*s; w = -0.4375*s*s; } ++its; for (m=(nn-2);m>=l;m--) { /* Form shift and then look for */ z=a[m][m]; /* 2 consecutive small sub- */ r=x-z; /* diagonal elements. */ s=y-z; p=(r*s-w)/a[m+1][m]+a[m][m+1]; /* Equation (11.6.23). */ q=a[m+1][m+1]-z-r-s; r=a[m+2][m+1]; s=fabs (p)+fabs (q)+fabs (r); /* Scale to prevent overflow or */ p /= s; /* underflow. */ q /= s; r /= s; if (m == l) break; u=fabs (a[m][m-1])*(fabs (q)+fabs (r)); v=fabs (p)*(fabs (a[m-1][m-1])+fabs (z)+fabs (a[m+1][m+1])); if ((double)(u+v) == v) break; /* Equation (11.6.26). */ } for (i=m+2;i<=nn;i++) { a[i][i-2]=0.0; if (i != (m+2)) a[i][i-3]=0.0; } for (k=m;k<=nn-1;k++) { /* Double QR step on rows l to nn and columns m to nn. */ if (k != m) { p=a[k][k-1]; /* Begin setup of Householder */ q=a[k+1][k-1]; /* vector. */ r=0.0; if (k != (nn-1)) r=a[k+2][k-1]; if ((x=fabs (p)+fabs (q)+fabs (r)) != 0.0) { p /= x; /* Scale to prevent overflow or */ q /= x; /* underflow. */ r /= x; } } if ((s=SIGN (sqrt (p*p+q*q+r*r),p)) != 0.0) { if (k == m) { if (l != m) a[k][k-1] = -a[k][k-1]; } else a[k][k-1] = -s*x; p += s; /* Equations (11.6.24). */ x=p/s; y=q/s; z=r/s; q /= p; r /= p; for (j=k;j<=nn;j++) { /* Row modification. */ p=a[k][j]+q*a[k+1][j]; if (k != (nn-1)) { p += r*a[k+2][j]; a[k+2][j] -= p*z; } a[k+1][j] -= p*y; a[k][j] -= p*x; } mmin = nng) { f /= RADIX; c /= sqrdx; } if ((c+r)/f < 0.95*s) { last=0; g=1.0/f; for (j=1;j<=n;j++) a[i][j] *= g; /* Apply similarity transformation */ for (j=1;j<=n;j++) a[j][i] *= f; } } } } } #define MAX_DEGREE 50 static void zrhqr (double a[], int m, double rtr[], double rti[]) /* Find all the roots of a polynomial with real coefficients, E(i=0..m) a(i)x^i, given the degree m and the coefficients a[0..m]. The method is to construct an upper Hessenberg matrix whose eigenvalues are the desired roots, and then use the routines balanc and hqr. The real and imaginary parts of the roots are returned in rtr[1..m] and rti[1..m], respectively. */ { int j,k; double **hess,xr,xi; hess=matrix (1,MAX_DEGREE,1,MAX_DEGREE); if (m > MAX_DEGREE || a[m] == 0.0 || /* TIMJ: */ fabs (a[m]) < 1e-15 ) nrerror ("bad args in zrhqr"); for (k=1;k<=m;k++) /* Construct the matrix. */ { hess[1][k] = -a[m-k]/a[m]; for (j=2;j<=m;j++) hess[j][k]=0.0; if (k != m) hess[k+1][k]=1.0; } balanc (hess,m); /* Find its eigenvalues. */ hqr (hess,m,rtr,rti); if (0) /* TIMJ: don't need sorting */ for (j=2;j<=m;j++) { /* Sort roots by their real parts by straight insertion. */ xr=rtr[j]; xi=rti[j]; for (k=j-1;k>=1;k--) { if (rtr[k] <= xr) break; rtr[k+1]=rtr[k]; rti[k+1]=rti[k]; } rtr[k+1]=xr; rti[k+1]=xi; } free_matrix (hess,1,MAX_DEGREE,1,MAX_DEGREE); } #define EPSS 2.0e-16 /* TIMJ, was(float): 1.0e-7 */ #define MR 8 #define MT 100 /* TIMJ: was: 10 */ #define MAXIT (MT*MR) /* Here EPSS is the estimated fractional roundoff error. We try to break (rare) limit cycles with MR different fractional values, once every MT steps, for MAXIT total allowed iterations. */ static void laguer (GslComplex a[], int m, GslComplex *x, int *its) /* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial mi=0 a[i]xi, and given a complex value x, this routine improves x by Laguerre's method until it converges, within the achievable roundoff limit, to a root of the given polynomial. The number of iterations taken is returned as its. */ { int iter,j; double abx,abp,abm,err; GslComplex dx,x1,b,d,f,g,h,sq,gp,gm,g2; static double frac[MR+1] = {0.0,0.5,0.25,0.75,0.13,0.38,0.62,0.88,1.0}; /* Fractions used to break a limit cycle. */ for (iter=1;iter<=MAXIT;iter++) { /* Loop over iterations up to allowed maximum. */ *its=iter; b=a[m]; err=gsl_complex_abs (b); d=f=gsl_complex (0.0,0.0); abx=gsl_complex_abs (*x); for (j=m-1;j>=0;j--) { /* Efficient computation of the polynomial and */ f=gsl_complex_add (gsl_complex_mul (*x,f),d); /* its first two derivatives. */ d=gsl_complex_add (gsl_complex_mul (*x,d),b); b=gsl_complex_add (gsl_complex_mul (*x,b),a[j]); err=gsl_complex_abs (b)+abx*err; } err *= EPSS; /* Estimate of roundoff error in evaluating polynomial. */ if (gsl_complex_abs (b) <= err) return; /* We are on the root. */ g=gsl_complex_div (d,b); /* The generic case: use Laguerre's formula. */ g2=gsl_complex_mul (g,g); h=gsl_complex_sub (g2,gsl_complex_rmul (2.0,gsl_complex_div (f,b))); sq=gsl_complex_sqrt (gsl_complex_rmul ((double) (m-1),gsl_complex_sub (gsl_complex_rmul ((double) m,h),g2))); gp=gsl_complex_add (g,sq); gm=gsl_complex_sub (g,sq); abp=gsl_complex_abs (gp); abm=gsl_complex_abs (gm); if (abp < abm) gp=gm; dx=((DMAX (abp,abm) > 0.0 ? gsl_complex_div (gsl_complex ((double) m,0.0),gp) : gsl_complex_rmul (1+abx,gsl_complex (cos ((double)iter),sin ((double)iter))))); x1=gsl_complex_sub (*x,dx); if (x->re == x1.re && x->im == x1.im) return; /* Converged. */ if (iter % MT) *x=x1; else *x=gsl_complex_sub (*x,gsl_complex_rmul (frac[iter/MT],dx)); /* Every so often we take a fractional step, to break any limit cycle (itself a rare occurrence). */ } nrerror ("too many iterations in laguer"); /* Very unusual - can occur only for complex roots. Try a different starting guess for the root. */ } /* Here is a driver routine that calls laguer in succession for each root, performs the deflation, optionally polishes the roots by the same Laguerre method - if you are not going to polish in some other way - and finally sorts the roots by their real parts. (We will use this routine in Chapter 13.) */ #define EPS 4.0e-15 /* TIMJ, was(float): 2.0e-6 */ #define MAXM 100 /* A small number, and maximum anticipated value of m. */ static void zroots (GslComplex a[], int m, GslComplex roots[], int polish) /* Given the degree m and the m+1 complex coefficients a[0..m] of the polynomial mi=0 a (i)xi, this routine successively calls laguer and finds all m complex roots in roots[1..m]. The boolean variable polish should be input as true (1) if polishing (also by Laguerre's method) is desired, false (0) if the roots will be subsequently polished by other means. */ { int i,its,j,jj; GslComplex x,b,c,ad[MAXM]; for (j=0;j<=m;j++) ad[j]=a[j]; /* Copy of coefficients for successive deflation. */ for (j=m;j>=1;j--) /* Loop over each root to be found. */ { x=gsl_complex (0.0,0.0); /* Start at zero to favor convergence to small- */ laguer (ad,j,&x,&its); /* est remaining root, and find the root. */ if (fabs (x.im) <= 2.0*EPS*fabs (x.re)) x.im=0.0; roots[j]=x; b=ad[j]; /* Forward deflation. */ for (jj=j-1;jj>=0;jj--) { c=ad[jj]; ad[jj]=b; b=gsl_complex_add (gsl_complex_mul (x,b),c); } } if (polish) for (j=1;j<=m;j++) /* Polish the roots using the undeflated coeffi- */ laguer (a,m,&roots[j],&its); /* cients. */ for (j=2;j<=m;j++) /* Sort roots by their real parts by straight insertion */ { x=roots[j]; for (i=j-1;i>=1;i--) { if (roots[i].re <= x.re) break; roots[i+1]=roots[i]; } roots[i+1]=x; } } #define ITMAX 20 /* At most ITMAX iterations. */ #define TINY 2.0-15 /* TIMJ, was (float): 1.0e-6 */ static void qroot (double p[], int n, double *b, double *c, double eps) /* Given n+1 coefficients p[0..n] of a polynomial of degree n, and trial values for the coefficients of a quadratic factor x*x+b*x+c, improve the solution until the coefficients b,c change by less than eps. The routine poldiv §5.3 is used. */ { int iter; double sc,sb,s,rc,rb,r,dv,delc,delb; double *q,*qq,*rem; double d[3]; q=vector (0,n); qq=vector (0,n); rem=vector (0,n); d[2]=1.0; for (iter=1;iter<=ITMAX;iter++) { d[1]=(*b); d[0]=(*c); poldiv (p,n,d,2,q,rem); s=rem[0]; /* First division r,s. */ r=rem[1]; poldiv (q,(n-1),d,2,qq,rem); sb = -(*c)*(rc = -rem[1]); /* Second division partial r,s with respect to */ rb = -(*b)*rc+(sc = -rem[0]); /* c. */ dv=1.0/(sb*rc-sc*rb); /* Solve 2x2 equation. */ delb=(r*sc-s*rc)*dv; delc=(-r*sb+s*rb)*dv; *b += (delb=(r*sc-s*rc)*dv); *c += (delc=(-r*sb+s*rb)*dv); if ((fabs (delb) <= eps*fabs (*b) || fabs (*b) < TINY) && (fabs (delc) <= eps*fabs (*c) || fabs (*c) < TINY)) { free_vector (rem,0,n); /* Coefficients converged. */ free_vector (qq,0,n); free_vector (q,0,n); return; } } nrerror ("Too many iterations in routine qroot"); } #define SNCNDN_CA 0.0003 /* The accuracy is the square of SNCNDN_CA. */ static void sncndn (double uu, double emmc, double *sn_p, double *cn_p, double *dn_p) /* Returns the Jacobian elliptic functions sn(u, kc), cn(u, kc), and dn(u, kc). Here uu = u, while emmc = k2c. */ { double a,b,c,d,emc,u,sn,cn,dn; double em[14],en[14]; int i,ii,l,bo; d=0; /* TIMJ: shutup compiler */ emc=emmc; u=uu; if (emc) { bo=(emc < 0.0); if (bo) { d=1.0-emc; emc /= -1.0/d; u *= (d=sqrt(d)); }a=1.0; dn=1.0; for (i=1;i<=13;i++) { l=i; em[i]=a; en[i]=(emc=sqrt(emc)); c=0.5*(a+emc); if (fabs(a-emc) <= SNCNDN_CA*a) break; emc *= a; a=c; }u *= c; sn=sin(u); cn=cos(u); if (sn) { a=cn/sn; c *= a; for (ii=l;ii>=1;ii--) { b=em[ii]; a *= c; c *= dn; dn=(en[ii]+a)/(b+a); a=c/b; }a=1.0/sqrt(c*c+1.0); sn=(sn >= 0.0 ? a : -a); cn=c*sn; }if (bo) { a=dn; dn=cn; cn=a; sn /= d; } } else { cn=1.0/cosh(u); dn=cn; sn=tanh(u); } if (sn_p) *sn_p = sn; if (cn_p) *cn_p = cn; if (dn_p) *dn_p = dn; } static void sncndnC (GslComplex uu, GslComplex emmc, GslComplex *sn_p, GslComplex *cn_p, GslComplex *dn_p) { GslComplex a,b,c,d,emc,u,sn,cn,dn; GslComplex em[14],en[14]; int i,ii,l,bo; emc=emmc; u=uu; if (emc.re || emc.im) /* gsl_complex_abs (emc)) */ { /* bo=gsl_complex_abs (emc) < 0.0; */ bo=emc.re < 0.0; if (bo) { d=gsl_complex_sub (ONE, emc); emc = gsl_complex_div (emc, gsl_complex_div (gsl_complex (-1.0, 0), d)); d = gsl_complex_sqrt (d); u = gsl_complex_mul (u, d); } a=ONE; dn=ONE; for (i=1;i<=13;i++) { l=i; em[i]=a; emc = gsl_complex_sqrt (emc); en[i]=emc; c = gsl_complex_mul (gsl_complex (0.5, 0), gsl_complex_add (a, emc)); if (gsl_complex_abs (gsl_complex_sub (a, emc)) <= gsl_complex_abs (gsl_complex_mul (gsl_complex (SNCNDN_CA, 0), a))) break; emc = gsl_complex_mul (emc, a); a=c; } u = gsl_complex_mul (u, c); sn = gsl_complex_sin (u); cn = gsl_complex_cos (u); if (sn.re) /* gsl_complex_abs (sn)) */ { a= gsl_complex_div (cn, sn); c = gsl_complex_mul (c, a); for (ii=l;ii>=1;ii--) { b = em[ii]; a = gsl_complex_mul (a, c); c = gsl_complex_mul (c, dn); dn = gsl_complex_div (gsl_complex_add (en[ii], a), gsl_complex_add (b, a)); a = gsl_complex_div (c, b); } a = gsl_complex_div (ONE, gsl_complex_sqrt (gsl_complex_add (ONE, gsl_complex_mul (c, c)))); if (sn.re >= 0.0) /* gsl_complex_arg (sn) >= 0.0) */ sn = a; else { sn.re = -a.re; sn.im = a.im; } cn = gsl_complex_mul (c, sn); } if (bo) { a=dn; dn=cn; cn=a; sn = gsl_complex_div (sn, d); } } else { cn=gsl_complex_div (ONE, gsl_complex_cosh (u)); dn=cn; sn=gsl_complex_tanh (u); } if (sn_p) *sn_p = sn; if (cn_p) *cn_p = cn; if (dn_p) *dn_p = dn; } #define RF_ERRTOL 0.0025 /* TIMJ, was(float): 0.08 */ #define RF_TINY 2.2e-307 /* TIMJ, was(float): 1.5e-38 */ #define RF_BIG 1.5e+307 /* TIMJ, was(float): 3.0e37 */ #define RF_THIRD (1.0/3.0) #define RF_C1 (1.0/24.0) #define RF_C2 0.1 #define RF_C3 (3.0/44.0) #define RF_C4 (1.0/14.0) static double rf (double x, double y, double z) /* Computes Carlson's elliptic integral of the first kind, RF (x, y, z). x, y, and z must be nonneg- ative, and at most one can be zero. RF_TINY must be at least 5 times the machine underflow limit, RF_BIG at most one fifth the machine overflow limit. */ { double alamb,ave,delx,dely,delz,e2,e3,sqrtx,sqrty,sqrtz,xt,yt,zt; if (1 /* TIMJ: add verbose checks */) { if (DMIN (DMIN (x, y), z) < 0.0) nrerror ("rf: x,y,z have to be positive"); if (DMIN (DMIN (x + y, x + z), y + z) < RF_TINY) nrerror ("rf: only one of x,y,z may be 0"); if (DMAX (DMAX (x, y), z) > RF_BIG) nrerror ("rf: at least one of x,y,z is too big"); } if (DMIN(DMIN(x,y),z) < 0.0 || DMIN(DMIN(x+y,x+z),y+z) < RF_TINY || DMAX(DMAX(x,y),z) > RF_BIG) nrerror("invalid arguments in rf"); xt=x; yt=y; zt=z; do { sqrtx=sqrt(xt); sqrty=sqrt(yt); sqrtz=sqrt(zt); alamb=sqrtx*(sqrty+sqrtz)+sqrty*sqrtz; xt=0.25*(xt+alamb); yt=0.25*(yt+alamb); zt=0.25*(zt+alamb); ave=RF_THIRD*(xt+yt+zt); delx=(ave-xt)/ave; dely=(ave-yt)/ave; delz=(ave-zt)/ave; } while (DMAX(DMAX(fabs(delx),fabs(dely)),fabs(delz)) > RF_ERRTOL); e2=delx*dely-delz*delz; e3=delx*dely*delz; return (1.0+(RF_C1*e2-RF_C2-RF_C3*e3)*e2+RF_C4*e3)/sqrt(ave); } static GslComplex rfC (GslComplex x, GslComplex y, GslComplex z) { GslComplex alamb,ave,delx,dely,delz,e2,e3,sqrtx,sqrty,sqrtz,xt,yt,zt; GslComplex RFC_C1 = {1.0/24.0, 0}, RFC_C2 = {0.1, 0}, RFC_C3 = {3.0/44.0, 0}, RFC_C4 = {1.0/14.0, 0}; if (DMIN (DMIN (gsl_complex_abs (x), gsl_complex_abs (y)), gsl_complex_abs (z)) < 0.0) nrerror ("rf: x,y,z have to be positive"); if (DMIN (DMIN (gsl_complex_abs (x) + gsl_complex_abs (y), gsl_complex_abs (x) + gsl_complex_abs (z)), gsl_complex_abs (y) + gsl_complex_abs (z)) < RF_TINY) nrerror ("rf: only one of x,y,z may be 0"); if (DMAX (DMAX (gsl_complex_abs (x), gsl_complex_abs (y)), gsl_complex_abs (z)) > RF_BIG) nrerror ("rf: at least one of x,y,z is too big"); xt=x; yt=y; zt=z; do { sqrtx = gsl_complex_sqrt (xt); sqrty = gsl_complex_sqrt (yt); sqrtz = gsl_complex_sqrt (zt); alamb = gsl_complex_add (gsl_complex_mul (sqrtx, gsl_complex_add (sqrty, sqrtz)), gsl_complex_mul (sqrty, sqrtz)); xt = gsl_complex_mul (gsl_complex (0.25, 0), gsl_complex_add (xt, alamb)); yt = gsl_complex_mul (gsl_complex (0.25, 0), gsl_complex_add (yt, alamb)); zt = gsl_complex_mul (gsl_complex (0.25, 0), gsl_complex_add (zt, alamb)); ave = gsl_complex_mul (gsl_complex (RF_THIRD, 0), gsl_complex_add3 (xt, yt, zt)); delx = gsl_complex_div (gsl_complex_sub (ave, xt), ave); dely = gsl_complex_div (gsl_complex_sub (ave, yt), ave); delz = gsl_complex_div (gsl_complex_sub (ave, zt), ave); /* } while (DMAX (DMAX (fabs (delx.re), fabs (dely.re)), fabs (delz.re)) > RF_ERRTOL); */ } while (DMAX (DMAX (gsl_complex_abs (delx), gsl_complex_abs (dely)), gsl_complex_abs (delz)) > RF_ERRTOL); e2 = gsl_complex_sub (gsl_complex_mul (delx, dely), gsl_complex_mul (delz, delz)); e3 = gsl_complex_mul3 (delx, dely, delz); return gsl_complex_div (gsl_complex_add3 (gsl_complex (1.0, 0), gsl_complex_mul (e2, gsl_complex_sub3 (gsl_complex_mul (RFC_C1, e2), RFC_C2, gsl_complex_mul (RFC_C3, e3))), gsl_complex_mul (RFC_C4, e3)), gsl_complex_sqrt (ave)); } static double ellf (double phi, double ak) /* Legendre elliptic integral of the 1st kind F(phi, k), evaluated using Carlson's function RF. The argument ranges are 0 <= phi <= pi/2, 0 <= k*sin(phi) <= 1. */ { double s=sin(phi); return s*rf(DSQR(cos(phi)),(1.0-s*ak)*(1.0+s*ak),1.0); }