Changes in explore/precision.py [237c9cf:2a602c7] in sasmodels
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
explore/precision.py
r237c9cf r2a602c7 1 1 #!/usr/bin/env python 2 2 r""" 3 Show numerical precision of $2 J_1(x)/x$. 3 Show numerical precision of various expressions. 4 5 Evaluates the same function(s) in single and double precision and compares 6 the results to 500 digit mpmath evaluation of the same function. 7 8 Note: a quick way to generation C and python code for taylor series 9 expansions from sympy: 10 11 import sympy as sp 12 x = sp.var("x") 13 f = sp.sin(x)/x 14 t = sp.series(f, n=12).removeO() # taylor series with no O(x^n) term 15 p = sp.horner(t) # Horner representation 16 p = p.replace(x**2, sp.var("xsq") # simplify if alternate terms are zero 17 p = p.n(15) # evaluate coefficients to 15 digits (optional) 18 c_code = sp.ccode(p, assign_to=sp.var("p")) # convert to c code 19 py_code = c[:-1] # strip semicolon to convert c to python 20 21 # mpmath has pade() rational function approximation, which might work 22 # better than the taylor series for some functions: 23 P, Q = mp.pade(sp.Poly(t.n(15),x).coeffs(), L, M) 24 P = sum(a*x**n for n,a in enumerate(reversed(P))) 25 Q = sum(a*x**n for n,a in enumerate(reversed(Q))) 26 c_code = sp.ccode(sp.horner(P)/sp.horner(Q), assign_to=sp.var("p")) 27 28 # There are richardson and shanks series accelerators in both sympy 29 # and mpmath that may be helpful. 4 30 """ 5 31 from __future__ import division, print_function … … 81 107 elif xrange == "linear": 82 108 lin_min, lin_max, lin_steps = 1, 1000, 2000 83 lin_min, lin_max, lin_steps = 0.001, 2, 200084 109 elif xrange == "log": 85 110 log_min, log_max, log_steps = -3, 5, 400 … … 287 312 ) 288 313 add_function( 314 name="expm1(x)", 315 mp_function=mp.expm1, 316 np_function=np.expm1, 317 ocl_function=make_ocl("return expm1(q);", "sas_expm1"), 318 limits=(-5., 5.), 319 ) 320 add_function( 289 321 name="arctan(x)", 290 322 mp_function=mp.atan, … … 322 354 np_function=lambda x: np.fmod(x, 2*np.pi), 323 355 ocl_function=make_ocl("return fmod(q, 2*M_PI);", "sas_fmod"), 324 )325 add_function(326 name="debye",327 mp_function=lambda x: 2*(mp.exp(-x**2) + x**2 - 1)/x**4,328 np_function=lambda x: 2*(np.expm1(-x**2) + x**2)/x**4,329 ocl_function=make_ocl("""330 const double qsq = q*q;331 if (qsq < 1.0) { // Pade approximation332 const double x = qsq;333 if (0) { // 0.36 single334 // PadeApproximant[2*Exp[-x^2] + x^2-1)/x^4, {x, 0, 4}]335 return (x*x/180. + 1.)/((1./30.*x + 1./3.)*x + 1);336 } else if (0) { // 1.0 for single337 // padeapproximant[2*exp[-x^2] + x^2-1)/x^4, {x, 0, 6}]338 const double A1=1./24., A2=1./84, A3=-1./3360;339 const double B1=3./8., B2=3./56., B3=1./336.;340 return (((A3*x + A2)*x + A1)*x + 1.)/(((B3*x + B2)*x + B1)*x + 1.);341 } else if (1) { // 1.0 for single, 0.25 for double342 // PadeApproximant[2*Exp[-x^2] + x^2-1)/x^4, {x, 0, 8}]343 const double A1=1./15., A2=1./60, A3=0., A4=1./75600.;344 const double B1=2./5., B2=1./15., B3=1./180., B4=1./5040.;345 return ((((A4*x + A3)*x + A2)*x + A1)*x + 1.)346 /((((B4*x + B3)*x + B2)*x + B1)*x + 1.);347 } else { // 1.0 for single, 0.5 for double348 // PadeApproximant[2*Exp[-x^2] + x^2-1)/x^4, {x, 0, 8}]349 const double A1=1./12., A2=2./99., A3=1./2640., A4=1./23760., A5=-1./1995840.;350 const double B1=5./12., B2=5./66., B3=1./132., B4=1./2376., B5=1./95040.;351 return (((((A5*x + A4)*x + A3)*x + A2)*x + A1)*x + 1.)352 /(((((B5*x + B4)*x + B3)*x + B2)*x + B1)*x + 1.);353 }354 } else if (qsq < 1.) { // Taylor series; 0.9 for single, 0.25 for double355 const double x = qsq;356 const double C0 = +1.;357 const double C1 = -1./3.;358 const double C2 = +1./12.;359 const double C3 = -1./60.;360 const double C4 = +1./360.;361 const double C5 = -1./2520.;362 const double C6 = +1./20160.;363 const double C7 = -1./181440.;364 //return ((((C5*x + C4)*x + C3)*x + C2)*x + C1)*x + C0;365 //return (((((C6*x + C5)*x + C4)*x + C3)*x + C2)*x + C1)*x + C0;366 return ((((((C7*x + C6)*x + C5)*x + C4)*x + C3)*x + C2)*x + C1)*x + C0;367 } else {368 return 2.*(expm1(-qsq) + qsq)/(qsq*qsq);369 }370 """, "sas_debye"),371 356 ) 372 357 … … 448 433 ) 449 434 435 replacement_expm1 = """\ 436 double x = (double)q; // go back to float for single precision kernels 437 // Adapted from the cephes math library. 438 // Copyright 1984 - 1992 by Stephen L. Moshier 439 if (x != x || x == 0.0) { 440 return x; // NaN and +/- 0 441 } else if (x < -0.5 || x > 0.5) { 442 return exp(x) - 1.0; 443 } else { 444 const double xsq = x*x; 445 const double p = ((( 446 +1.2617719307481059087798E-4)*xsq 447 +3.0299440770744196129956E-2)*xsq 448 +9.9999999999999999991025E-1); 449 const double q = (((( 450 +3.0019850513866445504159E-6)*xsq 451 +2.5244834034968410419224E-3)*xsq 452 +2.2726554820815502876593E-1)*xsq 453 +2.0000000000000000000897E0); 454 double r = x * p; 455 r = r / (q - r); 456 return r+r; 457 } 458 """ 459 add_function( 460 name="sas_expm1(x)", 461 mp_function=mp.expm1, 462 np_function=np.expm1, 463 ocl_function=make_ocl(replacement_expm1, "sas_expm1"), 464 ) 465 450 466 # Alternate versions of 3 j1(x)/x, for posterity 451 467 def taylor_3j1x_x(x):
Note: See TracChangeset
for help on using the changeset viewer.