/* w.c Copyright (c) Kapteyn Laboratorium Groningen 1992 All Right Reserved. #> w.dc2 Function: W Purpose: Error function for complex arguments. W(Z) = EXP(-Z*Z)ERFC(-iZ) Category: Files: w.c Author: Kor G. Begeman Use: COMPLEX W(Z) Input COMPLEX W The function value Z Complex argument Method: see Abromowitz and Stegun (chapter 7) - 6 Precision: |error| < 2 * 10 Updates: Dec 2, 1982 : KGB creation date Apr 28, 1986 : KGB migrated to VAX-VMS Nov 26, 1992 : KGB Migrated to UNIX-GIPSY #< Fortran to C interface: @ complex function w( complex ) */ #include "math.h" #include "stdio.h" #include "gipsyc.h" #define EPS ( 0.0000001 ) /* precision */ complex w_c( complex *z ) { complex r; /* return value */ double wdx = 0.0; /* real part result */ double wdy = 0.0; /* imag part result */ double x, y; /* real and imaginary arg */ x = fabs( (double) z->r ); /* real part */ y = fabs( (double) z->i ); /* imaginairy part */ if ( x > 6.0 || y > 6.0 ) { /* approximation for large arguments */ static double at[] = { 0.5124242, 0.05176536 }; static double bt[] = { 0.2752551, 2.72474500 }; int i; for ( i = 0; i < 2; i++ ) { double det, dtx, dty, sav; sav = ( x * x - y * y - bt[i] ); det = ( sav * sav + 4.0 * x * x * y * y ); dtx = ( 2.0 * x * x * y - y * sav ) * at[i]; dty = ( 2.0 * x * y * y + x * sav ) * at[i]; wdx += dtx / det; wdy += dty / det; } } else if ( x > 3.9 || y > 3.0 ) { /* approximation for intermediate arguments */ static double at[] = { 0.4613135, 0.09999216, 0.002883894 }; static double bt[] = { 0.1901635, 1.78449270, 5.525343700 }; int i; for ( i = 0; i < 3; i++ ) { double det, dtx, dty, sav; sav = ( x * x - y * y - bt[i] ); det = ( sav * sav + 4.0 * x * x * y * y ); dtx = ( 2.0 * x * x * y - y * sav ) * at[i]; dty = ( 2.0 * x * y * y + x * sav ) * at[i]; wdx += dtx / det; wdy += dty / det; } } else { /* no approximation */ double r; wdx = 1.0; r = sqrt( x * x + y * y ); if ( r > 0.0 ) { static double tt[] = { 1.0000000000, 0.5641895835 }; double tn[2]; double del, csp, snp, tcn, tsn; int n = 0; csp = -y / r; snp = x / r; tcn = 1.0; tsn = 0.0; tn[0] = tt[0]; tn[1] = tt[1]; do { double tc, ts; int i; n += 1; /* increment interation number */ tc = tcn; /* save */ ts = tsn; /* save */ tcn = ( tc * csp - ts * snp ); /* next cosine term */ tsn = ( ts * csp + tc * snp ); /* next sine term */ i = n%2; /* argument */ tn[i] *= ( 2.0 / (double) n ); tn[0] *= r; /* multiply with radius */ tn[1] *= r; /* multiply with radius */ del = tn[i]; /* increment */ wdx += ( tcn * del ); /* add increment */ wdy += ( tsn * del ); /* add increment */ } while ( del > EPS ); /* precision is reached */ } } if ( z->r >= 0.0 && z->i >= 0.0 ) { r.r = wdx; r.i = wdy; } else if ( z->r >= 0.0 && z->i < 0.0 ) { double csp, snp, sav; csp = cos( 2.0 * x * y ); snp = sin( 2.0 * x * y ); sav = exp( y * y - x * x ); r.r = sav * csp - wdx; r.i = sav * snp + wdy; } else if ( z->r < 0.0 && z->i >= 0.0 ) { r.r = wdx; r.i = -wdy; } else if ( z->r < 0.0 && z->i < 0.0 ) { double csp, snp, sav; csp = cos( 2.0 * x * y ); snp = sin( 2.0 * x * y ); sav = exp( y * y - x * x ); r.r = sav * csp - wdx; r.i = -sav * snp - wdy; } return( r ); /* return */ } #if defined(TESTBED) #include "cmain.h" MAIN_PROGRAM_ENTRY { complex w, z; double x, y; int i, j, k; for ( k = 0; k < 16; k++ ) { printf( " Y "); for ( i = 0; i < 5; i++ ) { x = k * 0.5 + i * 0.1; printf( " X = %3.1f ", x ); } printf( "\n" ); for ( j = 0; j < 91; j++ ) { y = j * 0.1; printf( "%3.1f", y ); for ( i = 0; i < 5; i++ ) { x = k * 0.5 + i * 0.1; z.r = x; z.i = -y; w = w_c( &z ); printf( " %9.6f %9.6f", (double) w.r, (double) w.i ); } printf( "\n" ); } printf( " \n" ); } return( 0 ); } #endif