1
0

mtst.c 11 KB

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