mtstl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /* mtst.c
  2. Consistency tests for math functions.
  3. With NTRIALS=10000, the following are typical results for
  4. an alleged IEEE long double precision arithmetic:
  5. Consistency test of math functions.
  6. Max and rms errors for 10000 random arguments.
  7. A = absolute error criterion (but relative if >1):
  8. Otherwise, estimate is of relative error
  9. x = cbrt( cube(x) ): max = 7.65E-20 rms = 4.39E-21
  10. x = atan( tan(x) ): max = 2.01E-19 rms = 3.96E-20
  11. x = sin( asin(x) ): max = 2.15E-19 rms = 3.00E-20
  12. x = sqrt( square(x) ): max = 0.00E+00 rms = 0.00E+00
  13. x = log( exp(x) ): max = 5.42E-20 A rms = 1.87E-21 A
  14. x = log2( exp2(x) ): max = 1.08E-19 A rms = 3.37E-21 A
  15. x = log10( exp10(x) ): max = 2.71E-20 A rms = 6.76E-22 A
  16. x = acosh( cosh(x) ): max = 3.13E-18 A rms = 3.21E-20 A
  17. x = pow( pow(x,a),1/a ): max = 1.25E-17 rms = 1.70E-19
  18. x = tanh( atanh(x) ): max = 1.08E-19 rms = 1.16E-20
  19. x = asinh( sinh(x) ): max = 1.03E-19 rms = 2.94E-21
  20. x = cos( acos(x) ): max = 1.63E-19 A rms = 4.37E-20 A
  21. lgam(x) = log(gamma(x)): max = 2.31E-19 A rms = 5.93E-20 A
  22. x = ndtri( ndtr(x) ): max = 5.07E-17 rms = 7.03E-19
  23. Legendre ellpk, ellpe: max = 7.59E-19 A rms = 1.72E-19 A
  24. Absolute error and only 2000 trials:
  25. Wronksian of Yn, Jn: max = 6.40E-18 A rms = 1.49E-19 A
  26. Relative error and only 100 trials:
  27. x = stdtri(stdtr(k,x) ): max = 6.73E-19 rms = 2.46E-19
  28. */
  29. /*
  30. Cephes Math Library Release 2.3: November, 1995
  31. Copyright 1984, 1987, 1988, 1995 by Stephen L. Moshier
  32. */
  33. #include <math.h>
  34. /* C9X spells lgam lgamma. */
  35. #define GLIBC2 0
  36. #define NTRIALS 10000
  37. #define WTRIALS (NTRIALS/5)
  38. #define STRTST 0
  39. /* Note, fabsl may be an intrinsic function. */
  40. #ifdef ANSIPROT
  41. extern long double fabsl ( long double );
  42. extern long double sqrtl ( long double );
  43. extern long double cbrtl ( long double );
  44. extern long double expl ( long double );
  45. extern long double logl ( long double );
  46. extern long double tanl ( long double );
  47. extern long double atanl ( long double );
  48. extern long double sinl ( long double );
  49. extern long double asinl ( long double );
  50. extern long double cosl ( long double );
  51. extern long double acosl ( long double );
  52. extern long double powl ( long double, long double );
  53. extern long double tanhl ( long double );
  54. extern long double atanhl ( long double );
  55. extern long double sinhl ( long double );
  56. extern long double asinhl ( long double );
  57. extern long double coshl ( long double );
  58. extern long double acoshl ( long double );
  59. extern long double exp2l ( long double );
  60. extern long double log2l ( long double );
  61. extern long double exp10l ( long double );
  62. extern long double log10l ( long double );
  63. extern long double gammal ( long double );
  64. extern long double lgaml ( long double );
  65. extern long double jnl ( int, long double );
  66. extern long double ynl ( int, long double );
  67. extern long double ndtrl ( long double );
  68. extern long double ndtril ( long double );
  69. extern long double stdtrl ( int, long double );
  70. extern long double stdtril ( int, long double );
  71. extern long double ellpel ( long double );
  72. extern long double ellpkl ( long double );
  73. extern void exit (int);
  74. #else
  75. long double fabsl(), sqrtl();
  76. long double cbrtl(), expl(), logl(), tanl(), atanl();
  77. long double sinl(), asinl(), cosl(), acosl(), powl();
  78. long double tanhl(), atanhl(), sinhl(), asinhl(), coshl(), acoshl();
  79. long double exp2l(), log2l(), exp10l(), log10l();
  80. long double gammal(), lgaml(), jnl(), ynl(), ndtrl(), ndtril();
  81. long double stdtrl(), stdtril(), ellpel(), ellpkl();
  82. void exit ();
  83. #endif
  84. extern int merror;
  85. #if GLIBC2
  86. long double lgammal(long double);
  87. #endif
  88. /*
  89. NYI:
  90. double iv(), kn();
  91. */
  92. /* Provide inverses for square root and cube root: */
  93. long double squarel(x)
  94. long double x;
  95. {
  96. return( x * x );
  97. }
  98. long double cubel(x)
  99. long double x;
  100. {
  101. return( x * x * x );
  102. }
  103. /* lookup table for each function */
  104. struct fundef
  105. {
  106. char *nam1; /* the function */
  107. long double (*name )();
  108. char *nam2; /* its inverse */
  109. long double (*inv )();
  110. int nargs; /* number of function arguments */
  111. int tstyp; /* type code of the function */
  112. long ctrl; /* relative error flag */
  113. long double arg1w; /* width of domain for 1st arg */
  114. long double arg1l; /* lower bound domain 1st arg */
  115. long arg1f; /* flags, e.g. integer arg */
  116. long double arg2w; /* same info for args 2, 3, 4 */
  117. long double arg2l;
  118. long arg2f;
  119. /*
  120. double arg3w;
  121. double arg3l;
  122. long arg3f;
  123. double arg4w;
  124. double arg4l;
  125. long arg4f;
  126. */
  127. };
  128. /* fundef.ctrl bits: */
  129. #define RELERR 1
  130. #define EXPSCAL 4
  131. /* fundef.tstyp test types: */
  132. #define POWER 1
  133. #define ELLIP 2
  134. #define GAMMA 3
  135. #define WRONK1 4
  136. #define WRONK2 5
  137. #define WRONK3 6
  138. #define STDTR 7
  139. /* fundef.argNf argument flag bits: */
  140. #define INT 2
  141. extern long double MINLOGL;
  142. extern long double MAXLOGL;
  143. extern long double PIL;
  144. extern long double PIO2L;
  145. /*
  146. define MINLOG -170.0
  147. define MAXLOG +170.0
  148. define PI 3.14159265358979323846
  149. define PIO2 1.570796326794896619
  150. */
  151. #define NTESTS 17
  152. struct fundef defs[NTESTS] = {
  153. {" cube", cubel, " cbrt", cbrtl, 1, 0, 1, 2000.0L, -1000.0L, 0,
  154. 0.0, 0.0, 0},
  155. {" tan", tanl, " atan", atanl, 1, 0, 1, 0.0L, 0.0L, 0,
  156. 0.0, 0.0, 0},
  157. {" asin", asinl, " sin", sinl, 1, 0, 1, 2.0L, -1.0L, 0,
  158. 0.0, 0.0, 0},
  159. {"square", squarel, " sqrt", sqrtl, 1, 0, 1, 170.0L, -85.0L, EXPSCAL,
  160. 0.0, 0.0, 0},
  161. {" exp", expl, " log", logl, 1, 0, 0, 340.0L, -170.0L, 0,
  162. 0.0, 0.0, 0},
  163. {" exp2", exp2l, " log2", log2l, 1, 0, 0, 340.0L, -170.0L, 0,
  164. 0.0, 0.0, 0},
  165. {" exp10", exp10l, " log10", log10l, 1, 0, 0, 340.0L, -170.0L, 0,
  166. 0.0, 0.0, 0},
  167. {" cosh", coshl, " acosh", acoshl, 1, 0, 0, 340.0L, 0.0L, 0,
  168. 0.0, 0.0, 0},
  169. {"pow", powl, "pow", powl, 2, POWER, 1, 25.0L, 0.0L, 0,
  170. 50.0, -25.0, 0},
  171. {" atanh", atanhl, " tanh", tanhl, 1, 0, 1, 2.0L, -1.0L, 0,
  172. 0.0, 0.0, 0},
  173. {" sinh", sinhl, " asinh", asinhl, 1, 0, 1, 340.0L, 0.0L, 0,
  174. 0.0, 0.0, 0},
  175. {" acos", acosl, " cos", cosl, 1, 0, 0, 2.0L, -1.0L, 0,
  176. 0.0, 0.0, 0},
  177. #if GLIBC2
  178. /*
  179. { "gamma", gammal, "lgammal", lgammal, 1, GAMMA, 0, 34.0, 0.0, 0,
  180. 0.0, 0.0, 0},
  181. */
  182. #else
  183. { "gamma", gammal, "lgam", lgaml, 1, GAMMA, 0, 34.0, 0.0, 0,
  184. 0.0, 0.0, 0},
  185. { " ndtr", ndtrl, " ndtri", ndtril, 1, 0, 1, 10.0L, -10.0L, 0,
  186. 0.0, 0.0, 0},
  187. {" ellpe", ellpel, " ellpk", ellpkl, 1, ELLIP, 0, 1.0L, 0.0L, 0,
  188. 0.0, 0.0, 0},
  189. { "stdtr", stdtrl, "stdtri", stdtril, 2, STDTR, 1, 4.0L, -2.0L, 0,
  190. 30.0, 1.0, INT},
  191. { " Jn", jnl, " Yn", ynl, 2, WRONK1, 0, 30.0, 0.1, 0,
  192. 40.0, -20.0, INT},
  193. #endif
  194. };
  195. static char *headrs[] = {
  196. "x = %s( %s(x) ): ",
  197. "x = %s( %s(x,a),1/a ): ", /* power */
  198. "Legendre %s, %s: ", /* ellip */
  199. "%s(x) = log(%s(x)): ", /* gamma */
  200. "Wronksian of %s, %s: ", /* wronk1 */
  201. "Wronksian of %s, %s: ", /* wronk2 */
  202. "Wronksian of %s, %s: ", /* wronk3 */
  203. "x = %s(%s(k,x) ): ", /* stdtr */
  204. };
  205. static long double y1 = 0.0;
  206. static long double y2 = 0.0;
  207. static long double y3 = 0.0;
  208. static long double y4 = 0.0;
  209. static long double a = 0.0;
  210. static long double x = 0.0;
  211. static long double y = 0.0;
  212. static long double z = 0.0;
  213. static long double e = 0.0;
  214. static long double max = 0.0;
  215. static long double rmsa = 0.0;
  216. static long double rms = 0.0;
  217. static long double ave = 0.0;
  218. static double da, db, dc, dd;
  219. int ldrand();
  220. int printf();
  221. int
  222. main()
  223. {
  224. long double (*fun )();
  225. long double (*ifun )();
  226. struct fundef *d;
  227. int i, k, itst;
  228. int m, ntr;
  229. ntr = NTRIALS;
  230. printf( "Consistency test of math functions.\n" );
  231. printf( "Max and rms errors for %d random arguments.\n",
  232. ntr );
  233. printf( "A = absolute error criterion (but relative if >1):\n" );
  234. printf( "Otherwise, estimate is of relative error\n" );
  235. /* Initialize machine dependent parameters to test near the
  236. * largest an smallest possible arguments. To compare different
  237. * machines, use the same test intervals for all systems.
  238. */
  239. defs[1].arg1w = PIL;
  240. defs[1].arg1l = -PIL/2.0;
  241. /*
  242. defs[3].arg1w = MAXLOGL;
  243. defs[3].arg1l = -MAXLOGL/2.0;
  244. defs[4].arg1w = 2.0*MAXLOGL;
  245. defs[4].arg1l = -MAXLOGL;
  246. defs[6].arg1w = 2.0*MAXLOGL;
  247. defs[6].arg1l = -MAXLOGL;
  248. defs[7].arg1w = MAXLOGL;
  249. defs[7].arg1l = 0.0;
  250. */
  251. /* Outer loop, on the test number: */
  252. for( itst=STRTST; itst<NTESTS; itst++ )
  253. {
  254. d = &defs[itst];
  255. m = 0;
  256. max = 0.0L;
  257. rmsa = 0.0L;
  258. ave = 0.0L;
  259. fun = d->name;
  260. ifun = d->inv;
  261. /* Smaller number of trials for Wronksians
  262. * (put them at end of list)
  263. */
  264. if( d->tstyp == WRONK1 )
  265. {
  266. ntr = WTRIALS;
  267. printf( "Absolute error and only %d trials:\n", ntr );
  268. }
  269. else if( d->tstyp == STDTR )
  270. {
  271. ntr = NTRIALS/100;
  272. printf( "Relative error and only %d trials:\n", ntr );
  273. }
  274. /*
  275. y1 = d->arg1l;
  276. y2 = d->arg1w;
  277. da = y1;
  278. db = y2;
  279. printf( "arg1l = %.4e, arg1w = %.4e\n", da, db );
  280. */
  281. printf( headrs[d->tstyp], d->nam2, d->nam1 );
  282. for( i=0; i<ntr; i++ )
  283. {
  284. m++;
  285. k = 0;
  286. /* make random number(s) in desired range(s) */
  287. switch( d->nargs )
  288. {
  289. default:
  290. goto illegn;
  291. case 2:
  292. ldrand( &a );
  293. a = d->arg2w * ( a - 1.0L ) + d->arg2l;
  294. if( d->arg2f & EXPSCAL )
  295. {
  296. a = expl(a);
  297. ldrand( &y2 );
  298. a -= 1.0e-13L * a * (y2 - 1.0L);
  299. }
  300. if( d->arg2f & INT )
  301. {
  302. k = a + 0.25L;
  303. a = k;
  304. }
  305. case 1:
  306. ldrand( &x );
  307. y1 = d->arg1l;
  308. y2 = d->arg1w;
  309. x = y2 * ( x - 1.0L ) + y1;
  310. if( x < y1 )
  311. x = y1;
  312. y1 += y2;
  313. if( x > y1 )
  314. x = y1;
  315. if( d->arg1f & EXPSCAL )
  316. {
  317. x = expl(x);
  318. ldrand( &y2 );
  319. x += 1.0e-13L * x * (y2 - 1.0L);
  320. }
  321. }
  322. /* compute function under test */
  323. switch( d->nargs )
  324. {
  325. case 1:
  326. switch( d->tstyp )
  327. {
  328. case ELLIP:
  329. y1 = ( *(fun) )(x);
  330. y2 = ( *(fun) )(1.0L-x);
  331. y3 = ( *(ifun) )(x);
  332. y4 = ( *(ifun) )(1.0L-x);
  333. break;
  334. #if 1
  335. case GAMMA:
  336. y = lgaml(x);
  337. x = logl( gammal(x) );
  338. break;
  339. #endif
  340. default:
  341. z = ( *(fun) )(x);
  342. y = ( *(ifun) )(z);
  343. }
  344. /*
  345. if( merror )
  346. {
  347. printf( "error: x = %.15e, z = %.15e, y = %.15e\n",
  348. (double )x, (double )z, (double )y );
  349. }
  350. */
  351. break;
  352. case 2:
  353. if( d->arg2f & INT )
  354. {
  355. switch( d->tstyp )
  356. {
  357. case WRONK1:
  358. y1 = (*fun)( k, x ); /* jn */
  359. y2 = (*fun)( k+1, x );
  360. y3 = (*ifun)( k, x ); /* yn */
  361. y4 = (*ifun)( k+1, x );
  362. break;
  363. case WRONK2:
  364. y1 = (*fun)( a, x ); /* iv */
  365. y2 = (*fun)( a+1.0L, x );
  366. y3 = (*ifun)( k, x ); /* kn */
  367. y4 = (*ifun)( k+1, x );
  368. break;
  369. default:
  370. z = (*fun)( k, x );
  371. y = (*ifun)( k, z );
  372. }
  373. }
  374. else
  375. {
  376. if( d->tstyp == POWER )
  377. {
  378. z = (*fun)( x, a );
  379. y = (*ifun)( z, 1.0L/a );
  380. }
  381. else
  382. {
  383. z = (*fun)( a, x );
  384. y = (*ifun)( a, z );
  385. }
  386. }
  387. break;
  388. default:
  389. illegn:
  390. printf( "Illegal nargs= %d", d->nargs );
  391. exit(1);
  392. }
  393. switch( d->tstyp )
  394. {
  395. case WRONK1:
  396. /* Jn, Yn */
  397. /* e = (y2*y3 - y1*y4) - 2.0L/(PIL*x);*/
  398. e = x*(y2*y3 - y1*y4) - 2.0L/PIL;
  399. break;
  400. case WRONK2:
  401. /* In, Kn */
  402. /* e = (y2*y3 + y1*y4) - 1.0L/x; */
  403. e = x*(y2*y3 + y1*y4) - 1.0L;
  404. break;
  405. case ELLIP:
  406. e = (y1-y3)*y4 + y3*y2 - PIO2L;
  407. break;
  408. default:
  409. e = y - x;
  410. break;
  411. }
  412. if( d->ctrl & RELERR )
  413. {
  414. if( x != 0.0L )
  415. e /= x;
  416. else
  417. printf( "warning, x == 0\n" );
  418. }
  419. else
  420. {
  421. if( fabsl(x) > 1.0L )
  422. e /= x;
  423. }
  424. ave += e;
  425. /* absolute value of error */
  426. if( e < 0 )
  427. e = -e;
  428. /* peak detect the error */
  429. if( e > max )
  430. {
  431. max = e;
  432. if( e > 1.0e-10L )
  433. {
  434. da = x;
  435. db = z;
  436. dc = y;
  437. dd = max;
  438. printf("x %.6E z %.6E y %.6E max %.4E\n",
  439. da, db, dc, dd );
  440. /*
  441. if( d->tstyp >= WRONK1 )
  442. {
  443. printf( "y1 %.4E y2 %.4E y3 %.4E y4 %.4E k %d x %.4E\n",
  444. (double )y1, (double )y2, (double )y3,
  445. (double )y4, k, (double )x );
  446. }
  447. */
  448. }
  449. /*
  450. printf("%.8E %.8E %.4E %6ld \n", x, y, max, n);
  451. printf("%d %.8E %.8E %.4E %6ld \n", k, x, y, max, n);
  452. printf("%.6E %.6E %.6E %.4E %6ld \n", a, x, y, max, n);
  453. printf("%.6E %.6E %.6E %.6E %.4E %6ld \n", a, b, x, y, max, n);
  454. printf("%.4E %.4E %.4E %.4E %.4E %.4E %6ld \n",
  455. a, b, c, x, y, max, n);
  456. */
  457. }
  458. /* accumulate rms error */
  459. e *= 1.0e16L; /* adjust range */
  460. rmsa += e * e; /* accumulate the square of the error */
  461. }
  462. /* report after NTRIALS trials */
  463. rms = 1.0e-16L * sqrtl( rmsa/m );
  464. da = max;
  465. db = rms;
  466. if(d->ctrl & RELERR)
  467. printf(" max = %.2E rms = %.2E\n", da, db );
  468. else
  469. printf(" max = %.2E A rms = %.2E A\n", da, db );
  470. } /* loop on itst */
  471. exit (0);
  472. return 0;
  473. }