test-slatec.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Part of slatec-bessel-c++
  2. // Check of SLATEC used under OpenMP, to avoid regression.
  3. #include <iostream>
  4. #include <iomanip>
  5. #include <random>
  6. #include <cmath>
  7. #include <chrono>
  8. #include "f2c/slatec.hpp"
  9. using std::cout, std::endl, std::flush;
  10. template <class ... A> inline std::string
  11. format(A && ... a)
  12. {
  13. std::ostringstream o; (o << ... << a); return o.str();
  14. }
  15. template <class X> inline auto sqr(X && x) { return x*x; }
  16. using clck = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
  17. std::chrono::high_resolution_clock,
  18. std::chrono::steady_clock>;
  19. static double
  20. toseconds(clck::duration const & t)
  21. {
  22. return std::chrono::duration<float, std::ratio<1, 1>>(t).count();
  23. }
  24. int main()
  25. {
  26. int const c_1 = 1;
  27. double const r_1 = 1.;
  28. int const N = 1000000;
  29. std::vector<double> x(N), y(N);
  30. std::mt19937 random_sequence(99);
  31. std::uniform_real_distribution<double> xydist(-1, 1);
  32. x[0] = 3.4;
  33. y[0] = 0.;
  34. for (unsigned i=1; i<x.size(); ++i) {
  35. x[i] = xydist(random_sequence);
  36. y[i] = xydist(random_sequence);
  37. }
  38. // threaded
  39. std::vector<double> re(N), im(N);
  40. {
  41. auto t0 = clck::now();
  42. #pragma omp parallel for
  43. for (unsigned i=0; i<x.size(); ++i) {
  44. int nz, ierr;
  45. zbesj_(&x[i], &y[i], &r_1, &c_1, &c_1, &re[i], &im[i], &nz, &ierr);
  46. }
  47. clck::duration t1 = clck::now()-t0;
  48. cout << "threaded " << toseconds(t1)*1e3 << "ms. " << endl;
  49. }
  50. // serial
  51. std::vector<double> re_ref(N), im_ref(N);
  52. {
  53. auto t0 = clck::now();
  54. for (unsigned i=0; i<x.size(); ++i) {
  55. int nz, ierr;
  56. zbesj_(&x[i], &y[i], &r_1, &c_1, &c_1, &re_ref[i], &im_ref[i], &nz, &ierr);
  57. }
  58. clck::duration t1 = clck::now()-t0;
  59. cout << "serial " << toseconds(t1)*1e3 << "ms. " << endl;
  60. }
  61. // check
  62. int failures = 0;
  63. for (unsigned i=0; i<x.size(); ++i) {
  64. double err = (sqr(re[i]-re_ref[i]) + sqr(im[i]-im_ref[i]));
  65. if (err!=0) {
  66. cout << format("error at ", i, " : ", err) << endl;
  67. ++failures;
  68. }
  69. }
  70. // check vs alt impl.
  71. {
  72. double err = sqrt(sqr(re[0]-std::cyl_bessel_j(1., x[0])) + sqr(im[0]-0.));
  73. if (!(err<=1e-15)) {
  74. cout << format("error omp vs alt : ", err) << endl;
  75. ++failures;
  76. }
  77. }
  78. {
  79. double err = sqrt(sqr(re_ref[0]-std::cyl_bessel_j(1., x[0])) + sqr(im_ref[0]-0.));
  80. if (!(err<=1e-15)) {
  81. cout << format("error serial vs alt : ", err) << endl;
  82. ++failures;
  83. }
  84. }
  85. // other misc checks
  86. {
  87. double const r_07 = 0.7;
  88. {
  89. double err = std::abs(dgamma_(&r_07)-std::tgamma(0.7));
  90. if (!(err<=1e-15)) {
  91. cout << format("error dgamma_ : ", err) << endl;
  92. ++failures;
  93. }
  94. }
  95. {
  96. int ierr = 99;
  97. double err = std::abs(dgamln_(&r_07, &ierr)-std::lgamma(0.7));
  98. if (!(err<=1e-15) || ierr!=0) {
  99. cout << format("error dgamln_ : ", err, " ierr: ", ierr) << endl;
  100. ++failures;
  101. }
  102. }
  103. double const r_m11 = -11.1;
  104. {
  105. double a = dlngam_(&r_m11);
  106. double b = std::lgamma(-11.1);
  107. double err = std::abs(a-b);
  108. cout << format("error dlngam_ a: ", a, " vs b: ", b, ", err: ", err) << endl;
  109. if (!(err<=2e-14)) {
  110. ++failures;
  111. }
  112. }
  113. }
  114. cout << "total " << failures << " failures." << endl;
  115. return failures;
  116. };