monot.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /* monot.c
  2. Floating point function test vectors.
  3. Arguments and function values are synthesized for NPTS points in
  4. the vicinity of each given tabulated test point. The points are
  5. chosen to be near and on either side of the likely function algorithm
  6. domain boundaries. Since the function programs change their methods
  7. at these points, major coding errors or monotonicity failures might be
  8. detected.
  9. August, 1998
  10. S. L. Moshier */
  11. #include <stdio.h>
  12. /* Avoid including math.h. */
  13. double frexp (double, int *);
  14. double ldexp (double, int);
  15. /* Number of test points to generate on each side of tabulated point. */
  16. #define NPTS 100
  17. /* Functions of one variable. */
  18. double exp (double);
  19. double log (double);
  20. double sin (double);
  21. double cos (double);
  22. double tan (double);
  23. double atan (double);
  24. double asin (double);
  25. double acos (double);
  26. double sinh (double);
  27. double cosh (double);
  28. double tanh (double);
  29. double asinh (double);
  30. double acosh (double);
  31. double atanh (double);
  32. double gamma (double);
  33. double fabs (double);
  34. double floor (double);
  35. struct oneargument
  36. {
  37. char *name; /* Name of the function. */
  38. double (*func) (double);
  39. double arg1; /* Function argument, assumed exact. */
  40. double answer1; /* Exact, close to function value. */
  41. double answer2; /* answer1 + answer2 has extended precision. */
  42. double derivative; /* dy/dx evaluated at x = arg1. */
  43. int thresh; /* Error report threshold. 2 = 1 ULP approx. */
  44. };
  45. /* Add this to error threshold test[i].thresh. */
  46. #define OKERROR 0
  47. /* Unit of relative error in test[i].thresh. */
  48. static double MACHEP = 1.1102230246251565404e-16;
  49. /* extern double MACHEP; */
  50. struct oneargument test1[] =
  51. {
  52. {"exp", exp, 1.0, 2.7182769775390625,
  53. 4.85091998273536028747e-6, 2.71828182845904523536, 2},
  54. {"exp", exp, -1.0, 3.678741455078125e-1,
  55. 5.29566362982159552377e-6, 3.678794411714423215955e-1, 2},
  56. {"exp", exp, 0.5, 1.648712158203125,
  57. 9.1124970031468486507878e-6, 1.64872127070012814684865, 2},
  58. {"exp", exp, -0.5, 6.065216064453125e-1,
  59. 9.0532673209236037995e-6, 6.0653065971263342360e-1, 2},
  60. {"exp", exp, 2.0, 7.3890533447265625,
  61. 2.75420408772723042746e-6, 7.38905609893065022723, 2},
  62. {"exp", exp, -2.0, 1.353302001953125e-1,
  63. 5.08304130019189399949e-6, 1.3533528323661269189e-1, 2},
  64. {"log", log, 1.41421356237309492343, 3.465728759765625e-1,
  65. 7.1430341006605745676897e-7, 7.0710678118654758708668e-1, 2},
  66. {"log", log, 7.07106781186547461715e-1, -3.46588134765625e-1,
  67. 1.45444856522566402246e-5, 1.41421356237309517417, 2},
  68. {"sin", sin, 7.85398163397448278999e-1, 7.0709228515625e-1,
  69. 1.4496030297502751942956e-5, 7.071067811865475460497e-1, 2},
  70. {"sin", sin, -7.85398163397448501044e-1, -7.071075439453125e-1,
  71. 7.62758764840238811175e-7, 7.07106781186547389040e-1, 2},
  72. {"sin", sin, 1.570796326794896558, 9.999847412109375e-1,
  73. 1.52587890625e-5, 6.12323399573676588613e-17, 2},
  74. {"sin", sin, -1.57079632679489678004, -1.0,
  75. 1.29302922820150306903e-32, -1.60812264967663649223e-16, 2},
  76. {"sin", sin, 4.712388980384689674, -1.0,
  77. 1.68722975549458979398e-32, -1.83697019872102976584e-16, 2},
  78. {"sin", sin, -4.71238898038468989604, 9.999847412109375e-1,
  79. 1.52587890625e-5, 3.83475850529283315008e-17, 2},
  80. {"cos", cos, 3.92699081698724139500E-1, 9.23873901367187500000E-1,
  81. 5.63114409926198633370E-6, -3.82683432365089757586E-1, 2},
  82. {"cos", cos, 7.85398163397448278999E-1, 7.07092285156250000000E-1,
  83. 1.44960302975460497458E-5, -7.07106781186547502752E-1, 2},
  84. {"cos", cos, 1.17809724509617241850E0, 3.82675170898437500000E-1,
  85. 8.26146665231415693919E-6, -9.23879532511286738554E-1, 2},
  86. {"cos", cos, 1.96349540849362069750E0, -3.82690429687500000000E-1,
  87. 6.99732241029898567203E-6, -9.23879532511286785419E-1, 2},
  88. {"cos", cos, 2.35619449019234483700E0, -7.07107543945312500000E-1,
  89. 7.62758765040545859856E-7, -7.07106781186547589348E-1, 2},
  90. {"cos", cos, 2.74889357189106897650E0, -9.23889160156250000000E-1,
  91. 9.62764496328487887036E-6, -3.82683432365089870728E-1, 2},
  92. {"cos", cos, 3.14159265358979311600E0, -1.00000000000000000000E0,
  93. 7.49879891330928797323E-33, -1.22464679914735317723E-16, 2},
  94. {"tan", tan, 7.85398163397448278999E-1, 9.999847412109375e-1,
  95. 1.52587890624387676600E-5, 1.99999999999999987754E0, 2},
  96. {"tan", tan, 1.17809724509617241850E0, 2.41419982910156250000E0,
  97. 1.37332715322352112604E-5, 6.82842712474618858345E0, 2},
  98. {"tan", tan, 1.96349540849362069750E0, -2.41421508789062500000E0,
  99. 1.52551752942854759743E-6, 6.82842712474619262118E0, 2},
  100. {"tan", tan, 2.35619449019234483700E0, -1.00001525878906250000E0,
  101. 1.52587890623163029801E-5, 2.00000000000000036739E0, 2},
  102. {"tan", tan, 2.74889357189106897650E0, -4.14215087890625000000E-1,
  103. 1.52551752982565655126E-6, 1.17157287525381000640E0, 2},
  104. {"atan", atan, 4.14213562373094923430E-1, 3.92684936523437500000E-1,
  105. 1.41451752865477964149E-5, 8.53553390593273837869E-1, 2},
  106. {"atan", atan, 1.0, 7.85385131835937500000E-1,
  107. 1.30315615108096156608E-5, 0.5, 2},
  108. {"atan", atan, 2.41421356237309492343E0, 1.17808532714843750000E0,
  109. 1.19179477349460632350E-5, 1.46446609406726250782E-1, 2},
  110. {"atan", atan, -2.41421356237309514547E0, -1.17810058593750000000E0,
  111. 3.34084132752141908545E-6, 1.46446609406726227789E-1, 2},
  112. {"atan", atan, -1.0, -7.85400390625000000000E-1,
  113. 2.22722755169038433915E-6, 0.5, 2},
  114. {"atan", atan, -4.14213562373095145475E-1, -3.92700195312500000000E-1,
  115. 1.11361377576267665972E-6, 8.53553390593273703853E-1, 2},
  116. {"asin", asin, 3.82683432365089615246E-1, 3.92684936523437500000E-1,
  117. 1.41451752864854321970E-5, 1.08239220029239389286E0, 2},
  118. {"asin", asin, 0.5, 5.23590087890625000000E-1,
  119. 8.68770767387307710723E-6, 1.15470053837925152902E0, 2},
  120. {"asin", asin, 7.07106781186547461715E-1, 7.85385131835937500000E-1,
  121. 1.30315615107209645016E-5, 1.41421356237309492343E0, 2},
  122. {"asin", asin, 9.23879532511286738483E-1, 1.17808532714843750000E0,
  123. 1.19179477349183147612E-5, 2.61312592975275276483E0, 2},
  124. {"asin", asin, -0.5, -5.23605346679687500000E-1,
  125. 6.57108138862692289277E-6, 1.15470053837925152902E0, 2},
  126. {"acos", acos, 1.95090322016128192573E-1, 1.37443542480468750000E0,
  127. 1.13611408471185777914E-5, -1.01959115820831832232E0, 2},
  128. {"acos", acos, 3.82683432365089615246E-1, 1.17808532714843750000E0,
  129. 1.19179477351337991247E-5, -1.08239220029239389286E0, 2},
  130. {"acos", acos, 0.5, 1.04719543457031250000E0,
  131. 2.11662628524615421446E-6, -1.15470053837925152902E0, 2},
  132. {"acos", acos, 7.07106781186547461715E-1, 7.85385131835937500000E-1,
  133. 1.30315615108982668201E-5, -1.41421356237309492343E0, 2},
  134. {"acos", acos, 9.23879532511286738483E-1, 3.92684936523437500000E-1,
  135. 1.41451752867009165605E-5, -2.61312592975275276483E0, 2},
  136. {"acos", acos, 9.80785280403230430579E-1, 1.96334838867187500000E-1,
  137. 1.47019821746724723933E-5, -5.12583089548300990774E0, 2},
  138. {"acos", acos, -0.5, 2.09439086914062500000E0,
  139. 4.23325257049230842892E-6, -1.15470053837925152902E0, 2},
  140. {"sinh", sinh, 1.0, 1.17518615722656250000E0,
  141. 1.50364172389568823819E-5, 1.54308063481524377848E0, 2},
  142. {"sinh", sinh, 7.09089565712818057364E2, 4.49423283712885057274E307,
  143. 4.25947714184369757620E208, 4.49423283712885057274E307, 2},
  144. {"sinh", sinh, 2.22044604925031308085E-16, 0.00000000000000000000E0,
  145. 2.22044604925031308085E-16, 1.00000000000000000000E0, 2},
  146. {"cosh", cosh, 7.09089565712818057364E2, 4.49423283712885057274E307,
  147. 4.25947714184369757620E208, 4.49423283712885057274E307, 2},
  148. {"cosh", cosh, 1.0, 1.54307556152343750000E0,
  149. 5.07329180627847790562E-6, 1.17520119364380145688E0, 2},
  150. {"cosh", cosh, 0.5, 1.12762451171875000000E0,
  151. 1.45348763078522622516E-6, 5.21095305493747361622E-1, 2},
  152. {"tanh", tanh, 0.5, 4.62112426757812500000E-1,
  153. 4.73050219725850231848E-6, 7.86447732965927410150E-1, 2},
  154. {"tanh", tanh, 5.49306144334054780032E-1, 4.99984741210937500000E-1,
  155. 1.52587890624507506378E-5, 7.50000000000000049249E-1, 2},
  156. {"tanh", tanh, 0.625, 5.54595947265625000000E-1,
  157. 3.77508375729399903910E-6, 6.92419147969988069631E-1, 2},
  158. {"asinh", asinh, 0.5, 4.81201171875000000000E-1,
  159. 1.06531846034474977589E-5, 8.94427190999915878564E-1, 2},
  160. {"asinh", asinh, 1.0, 8.81362915039062500000E-1,
  161. 1.06719804805252326093E-5, 7.07106781186547524401E-1, 2},
  162. {"asinh", asinh, 2.0, 1.44363403320312500000E0,
  163. 1.44197568534249327674E-6, 4.47213595499957939282E-1, 2},
  164. {"acosh", acosh, 2.0, 1.31695556640625000000E0,
  165. 2.33051856670862504635E-6, 5.77350269189625764509E-1, 2},
  166. {"acosh", acosh, 1.5, 9.62417602539062500000E-1,
  167. 6.04758014439499551783E-6, 8.94427190999915878564E-1, 2},
  168. {"acosh", acosh, 1.03125, 2.49343872070312500000E-1,
  169. 9.62177257298785143908E-6, 3.96911150685467059809E0, 2},
  170. {"atanh", atanh, 0.5, 5.49301147460937500000E-1,
  171. 4.99687311734569762262E-6, 1.33333333333333333333E0, 2},
  172. #if 0
  173. {"gamma", gamma, 1.0, 1.0,
  174. 0.0, -5.772156649015328606e-1, 2},
  175. {"gamma", gamma, 2.0, 1.0,
  176. 0.0, 4.2278433509846713939e-1, 2},
  177. {"gamma", gamma, 3.0, 2.0,
  178. 0.0, 1.845568670196934279, 2},
  179. {"gamma", gamma, 4.0, 6.0,
  180. 0.0, 7.536706010590802836, 2},
  181. #endif
  182. {"null", NULL, 0.0, 0.0, 0.0, 2},
  183. };
  184. /* These take care of extra-precise floating point register problems. */
  185. volatile double volat1;
  186. volatile double volat2;
  187. /* Return the next nearest floating point value to X
  188. in the direction of UPDOWN (+1 or -1).
  189. (Fails if X is denormalized.) */
  190. double
  191. nextval (x, updown)
  192. double x;
  193. int updown;
  194. {
  195. double m;
  196. int i;
  197. volat1 = x;
  198. m = 0.25 * MACHEP * volat1 * updown;
  199. volat2 = volat1 + m;
  200. if (volat2 != volat1)
  201. printf ("successor failed\n");
  202. for (i = 2; i < 10; i++)
  203. {
  204. volat2 = volat1 + i * m;
  205. if (volat1 != volat2)
  206. return volat2;
  207. }
  208. printf ("nextval failed\n");
  209. return volat1;
  210. }
  211. int
  212. main ()
  213. {
  214. double (*fun1) (double);
  215. int i, j, errs, tests;
  216. double x, x0, y, dy, err;
  217. /* Set math coprocessor to double precision. */
  218. /* dprec (); */
  219. errs = 0;
  220. tests = 0;
  221. i = 0;
  222. for (;;)
  223. {
  224. fun1 = test1[i].func;
  225. if (fun1 == NULL)
  226. break;
  227. volat1 = test1[i].arg1;
  228. x0 = volat1;
  229. x = volat1;
  230. for (j = 0; j <= NPTS; j++)
  231. {
  232. volat1 = x - x0;
  233. dy = volat1 * test1[i].derivative;
  234. dy = test1[i].answer2 + dy;
  235. volat1 = test1[i].answer1 + dy;
  236. volat2 = (*(fun1)) (x);
  237. if (volat2 != volat1)
  238. {
  239. /* Report difference between program result
  240. and extended precision function value. */
  241. err = volat2 - test1[i].answer1;
  242. err = err - dy;
  243. err = err / volat1;
  244. if (fabs (err) > ((OKERROR + test1[i].thresh) * MACHEP))
  245. {
  246. printf ("%d %s(%.16e) = %.16e, rel err = %.3e\n",
  247. j, test1[i].name, x, volat2, err);
  248. errs += 1;
  249. }
  250. }
  251. x = nextval (x, 1);
  252. tests += 1;
  253. }
  254. x = x0;
  255. x = nextval (x, -1);
  256. for (j = 1; j < NPTS; j++)
  257. {
  258. volat1 = x - x0;
  259. dy = volat1 * test1[i].derivative;
  260. dy = test1[i].answer2 + dy;
  261. volat1 = test1[i].answer1 + dy;
  262. volat2 = (*(fun1)) (x);
  263. if (volat2 != volat1)
  264. {
  265. err = volat2 - test1[i].answer1;
  266. err = err - dy;
  267. err = err / volat1;
  268. if (fabs (err) > ((OKERROR + test1[i].thresh) * MACHEP))
  269. {
  270. printf ("%d %s(%.16e) = %.16e, rel err = %.3e\n",
  271. j, test1[i].name, x, volat2, err);
  272. errs += 1;
  273. }
  274. }
  275. x = nextval (x, -1);
  276. tests += 1;
  277. }
  278. i += 1;
  279. }
  280. printf ("%d errors in %d tests\n", errs, tests);
  281. }