math_utils.txx 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #include <omp.h>
  2. #include <cmath>
  3. #include <cstring>
  4. #include <cstdlib>
  5. #include <iostream>
  6. #include <iomanip>
  7. #include <vector>
  8. namespace SCTL_NAMESPACE {
  9. template <class Real, Integer bits = sizeof(Real)*8> struct GetSigBits {
  10. static constexpr Integer value() {
  11. return ((Real)(pow<bits>((Real)0.5)+1) == (Real)1 ? GetSigBits<Real,bits-1>::value() : bits);
  12. }
  13. };
  14. template <class Real> struct GetSigBits<Real,0> {
  15. static constexpr Integer value() {
  16. return 0;
  17. }
  18. };
  19. template <class Real> inline constexpr Integer significant_bits() {
  20. return GetSigBits<Real>::value();
  21. }
  22. template <class Real> inline constexpr Real machine_eps() {
  23. return pow<-GetSigBits<Real>::value()-1,Real>(2);
  24. }
  25. template <class Real> inline Real atoreal(const char* str) { // Warning: does not do correct rounding
  26. const auto get_num = [](const char* str, int& end) {
  27. Real val = 0, exp = 1;
  28. for (int i = end-1; i >= 0; i--) {
  29. char c = str[i];
  30. if ('0' <= c && c <= '9') {
  31. val += (c - '0') * exp;
  32. exp *= 10;
  33. } else if (c == '.') {
  34. val /= exp;
  35. exp = 1;
  36. } else if (c == '-') {
  37. val = -val;
  38. end = i - 1;
  39. break;
  40. } else if (c == '+') {
  41. end = i - 1;
  42. break;
  43. } else {
  44. end = i;
  45. break;
  46. }
  47. }
  48. return val;
  49. };
  50. Real val = 0;
  51. int i = std::strlen(str);
  52. for (; i > 0; i--) { // ignore trailing non-numeric characters
  53. if ('0' <= str[i-1] && str[i-1] <= '9') break;
  54. }
  55. val = get_num(str, i);
  56. if (i>0 && (str[i] == 'e' || str[i] == 'E')) {
  57. i--;
  58. val = get_num(str, i) * sctl::pow<Real,Real>((Real)10, val);
  59. }
  60. for (; i >= 0; i--) { // ignore leading whitespace
  61. SCTL_ASSERT(str[i] == ' ');
  62. }
  63. return val;
  64. }
  65. template <class Real> static inline constexpr Real const_pi_generic() {
  66. return 113187804032455044LL*pow<-55,Real>(2) + 59412220499329904LL*pow<-112,Real>(2);
  67. }
  68. template <class Real> static inline constexpr Real const_e_generic() {
  69. return 97936424237889173LL*pow<-55,Real>(2) + 30046841068362992LL*pow<-112,Real>(2);
  70. }
  71. template <class Real> static inline constexpr Real fabs_generic(const Real a) {
  72. return (a<0?-a:a);
  73. }
  74. template <class Real> static inline Real sqrt_generic(const Real a) {
  75. Real b = ::sqrt((double)a);
  76. if (a > 0) { // Newton iterations for greater accuracy
  77. b = (b + a / b) * 0.5;
  78. b = (b + a / b) * 0.5;
  79. }
  80. return b;
  81. }
  82. template <class Real> static inline Real sin_generic(const Real a) {
  83. const int N = 200;
  84. static std::vector<Real> theta;
  85. static std::vector<Real> sinval;
  86. static std::vector<Real> cosval;
  87. if (theta.size() == 0) {
  88. #pragma omp critical(SCTL_QUAD_SIN)
  89. if (theta.size() == 0) {
  90. sinval.resize(N);
  91. cosval.resize(N);
  92. Real t = 1.0;
  93. std::vector<Real> theta_(N);
  94. for (int i = 0; i < N; i++) {
  95. theta_[i] = t;
  96. t = t * 0.5;
  97. }
  98. sinval[N - 1] = theta_[N - 1];
  99. cosval[N - 1] = 1.0 - sinval[N - 1] * sinval[N - 1] / 2;
  100. for (int i = N - 2; i >= 0; i--) {
  101. sinval[i] = 2.0 * sinval[i + 1] * cosval[i + 1];
  102. cosval[i] = cosval[i + 1] * cosval[i + 1] - sinval[i + 1] * sinval[i + 1];
  103. Real s = 1 / sqrt<Real>(cosval[i] * cosval[i] + sinval[i] * sinval[i]);
  104. sinval[i] *= s;
  105. cosval[i] *= s;
  106. }
  107. theta_.swap(theta);
  108. }
  109. }
  110. Real t = (a < 0.0 ? -a : a);
  111. Real sval = 0.0;
  112. Real cval = 1.0;
  113. for (int i = 0; i < N; i++) {
  114. while (theta[i] <= t) {
  115. Real sval_ = sval * cosval[i] + cval * sinval[i];
  116. Real cval_ = cval * cosval[i] - sval * sinval[i];
  117. sval = sval_;
  118. cval = cval_;
  119. t = t - theta[i];
  120. }
  121. }
  122. return (a < 0.0 ? -sval : sval);
  123. }
  124. template <class Real> static inline Real cos_generic(const Real a) {
  125. const int N = 200;
  126. static std::vector<Real> theta;
  127. static std::vector<Real> sinval;
  128. static std::vector<Real> cosval;
  129. if (theta.size() == 0) {
  130. #pragma omp critical(SCTL_QUAD_COS)
  131. if (theta.size() == 0) {
  132. sinval.resize(N);
  133. cosval.resize(N);
  134. Real t = 1.0;
  135. std::vector<Real> theta_(N);
  136. for (int i = 0; i < N; i++) {
  137. theta_[i] = t;
  138. t = t * 0.5;
  139. }
  140. sinval[N - 1] = theta_[N - 1];
  141. cosval[N - 1] = 1.0 - sinval[N - 1] * sinval[N - 1] / 2;
  142. for (int i = N - 2; i >= 0; i--) {
  143. sinval[i] = 2.0 * sinval[i + 1] * cosval[i + 1];
  144. cosval[i] = cosval[i + 1] * cosval[i + 1] - sinval[i + 1] * sinval[i + 1];
  145. Real s = 1 / sqrt<Real>(cosval[i] * cosval[i] + sinval[i] * sinval[i]);
  146. sinval[i] *= s;
  147. cosval[i] *= s;
  148. }
  149. theta_.swap(theta);
  150. }
  151. }
  152. Real t = (a < 0.0 ? -a : a);
  153. Real sval = 0.0;
  154. Real cval = 1.0;
  155. for (int i = 0; i < N; i++) {
  156. while (theta[i] <= t) {
  157. Real sval_ = sval * cosval[i] + cval * sinval[i];
  158. Real cval_ = cval * cosval[i] - sval * sinval[i];
  159. sval = sval_;
  160. cval = cval_;
  161. t = t - theta[i];
  162. }
  163. }
  164. return cval;
  165. }
  166. template <class Real> static inline Real acos_generic(const Real a) {
  167. Real b = ::acos((double)a);
  168. if (b > 0) { // Newton iterations for greater accuracy
  169. b += (cos<Real>(b)-a)/sin<Real>(b);
  170. b += (cos<Real>(b)-a)/sin<Real>(b);
  171. }
  172. return b;
  173. }
  174. template <class Real> static inline Real exp_generic(const Real a) {
  175. const int N = 200;
  176. static std::vector<Real> theta0;
  177. static std::vector<Real> theta1;
  178. static std::vector<Real> expval0;
  179. static std::vector<Real> expval1;
  180. if (theta0.size() == 0) {
  181. #pragma omp critical(SCTL_QUAD_EXP)
  182. if (theta0.size() == 0) {
  183. std::vector<Real> theta0_(N);
  184. theta1.resize(N);
  185. expval0.resize(N);
  186. expval1.resize(N);
  187. theta0_[0] = 1.0;
  188. theta1[0] = 1.0;
  189. expval0[0] = const_e<Real>();
  190. expval1[0] = const_e<Real>();
  191. for (int i = 1; i < N; i++) {
  192. theta0_[i] = theta0_[i - 1] * 0.5;
  193. theta1[i] = theta1[i - 1] * 2.0;
  194. expval0[i] = sqrt<Real>(expval0[i - 1]);
  195. expval1[i] = expval1[i - 1] * expval1[i - 1];
  196. }
  197. theta0.swap(theta0_);
  198. }
  199. }
  200. Real t = (a < 0.0 ? -a : a);
  201. Real eval = 1.0;
  202. for (int i = N - 1; i > 0; i--) {
  203. while (theta1[i] <= t) {
  204. eval = eval * expval1[i];
  205. t = t - theta1[i];
  206. }
  207. }
  208. for (int i = 0; i < N; i++) {
  209. while (theta0[i] <= t) {
  210. eval = eval * expval0[i];
  211. t = t - theta0[i];
  212. }
  213. }
  214. eval = eval * (1.0 + t);
  215. return (a < 0.0 ? 1.0 / eval : eval);
  216. }
  217. template <class Real> static inline Real log_generic(const Real a) {
  218. if (a == 0) return (Real)NAN;
  219. Real y0 = ::log((double)a);
  220. { // Newton iterations
  221. y0 = y0 + (a / exp<Real>(y0) - 1.0);
  222. y0 = y0 + (a / exp<Real>(y0) - 1.0);
  223. }
  224. return y0;
  225. }
  226. template <class Real> static inline Real pow_generic(const Real b, const Real e) {
  227. if (e == 0) return 1;
  228. if (b == 0) return 0;
  229. if (b < 0) {
  230. Long e_ = (Long)e;
  231. SCTL_ASSERT(e == (Real)e_);
  232. return exp<Real>(log<Real>(-b) * e) * (e_ % 2 ? (Real)-1 : (Real)1.0);
  233. }
  234. return exp<Real>(log<Real>(b) * e);
  235. }
  236. template <class ValueType> static inline constexpr ValueType pow_integer_exp(ValueType b, Long e) {
  237. return (e > 0) ? ((e & 1) ? b : ValueType(1)) * pow_integer_exp(b*b, e>>1) : ValueType(1);
  238. }
  239. template <class Real, class ExpType> class pow_wrapper {
  240. public:
  241. static Real pow(Real b, ExpType e) {
  242. return (Real)std::pow(b, e);
  243. }
  244. };
  245. template <class ValueType> class pow_wrapper<ValueType,Long> {
  246. public:
  247. static constexpr ValueType pow(ValueType b, Long e) {
  248. return (e > 0) ? pow_integer_exp(b, e) : 1/pow_integer_exp(b, -e);
  249. }
  250. };
  251. template <Long e, class ValueType> inline constexpr ValueType pow(ValueType b) {
  252. return (e > 0) ? pow_integer_exp<ValueType>(b, e) : 1/pow_integer_exp<ValueType>(b, -e);
  253. }
  254. template <class Real> inline std::ostream& ostream_insertion_generic(std::ostream& output, const Real q_) {
  255. // int width=output.width();
  256. output << std::setw(1);
  257. Real q = q_;
  258. if (q < 0.0) {
  259. output << "-";
  260. q = -q;
  261. } else if (q > 0) {
  262. output << " ";
  263. } else {
  264. output << " ";
  265. output << "0.0";
  266. return output;
  267. }
  268. int exp = 0;
  269. static const Real ONETENTH = (Real)1 / 10;
  270. while (q < 1.0 && abs(exp) < 10000) {
  271. q = q * 10;
  272. exp--;
  273. }
  274. while (q >= 10 && abs(exp) < 10000) {
  275. q = q * ONETENTH;
  276. exp++;
  277. }
  278. for (int i = 0; i < 34; i++) {
  279. output << (int)q;
  280. if (i == 0) output << ".";
  281. q = (q - int(q)) * 10;
  282. if (q == 0 && i > 0) break;
  283. }
  284. if (exp > 0) {
  285. std::cout << "e+" << exp;
  286. } else if (exp < 0) {
  287. std::cout << "e" << exp;
  288. }
  289. return output;
  290. }
  291. #ifdef SCTL_QUAD_T
  292. template <> inline constexpr QuadReal const_pi<QuadReal>() { return const_pi_generic<QuadReal>(); }
  293. template <> inline constexpr QuadReal const_e<QuadReal>() { return const_e_generic<QuadReal>(); }
  294. template <> inline QuadReal fabs<QuadReal>(const QuadReal a) { return fabs_generic(a); }
  295. template <> inline QuadReal sqrt<QuadReal>(const QuadReal a) { return sqrt_generic(a); }
  296. template <> inline QuadReal sin<QuadReal>(const QuadReal a) { return sin_generic(a); }
  297. template <> inline QuadReal cos<QuadReal>(const QuadReal a) { return cos_generic(a); }
  298. template <> inline QuadReal acos<QuadReal>(const QuadReal a) { return acos_generic(a); }
  299. template <> inline QuadReal exp<QuadReal>(const QuadReal a) { return exp_generic(a); }
  300. template <> inline QuadReal log<QuadReal>(const QuadReal a) { return log_generic(a); }
  301. template <class ExpType> class pow_wrapper<QuadReal,ExpType> {
  302. public:
  303. static QuadReal pow(QuadReal b, ExpType e) {
  304. return pow_generic<QuadReal>(b, (QuadReal)e);
  305. }
  306. };
  307. template <> class pow_wrapper<QuadReal,Long> {
  308. public:
  309. static constexpr QuadReal pow(QuadReal b, Long e) {
  310. return (e > 0) ? pow_integer_exp(b, e) : 1/pow_integer_exp(b, -e);
  311. }
  312. };
  313. inline std::ostream& operator<<(std::ostream& output, const QuadReal& q) { return ostream_insertion_generic(output, q); }
  314. inline std::istream& operator>>(std::istream& inputstream, QuadReal& x) {
  315. long double x_;
  316. inputstream>>x_;
  317. x = x_;
  318. return inputstream;
  319. }
  320. #endif
  321. template <class Real, class ExpType> inline Real pow(const Real b, const ExpType e) {
  322. return pow_wrapper<Real,ExpType>::pow(b, e);
  323. }
  324. } // end namespace