math_compat.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #pragma once
  2. #include <cmath>
  3. // Android NDK platform < 21 with libstdc++ has spotty C++11 support.
  4. // Various hacks in this header allow the rest of the codebase to use
  5. // standard APIs.
  6. #if (defined(__ANDROID__) && __ANDROID_API__ < 21 && defined(__GLIBCXX__)) || \
  7. defined(__NEWLIB__)
  8. #include <stdexcept>
  9. namespace std {
  10. // Import double versions of these functions from the global namespace.
  11. using ::acosh;
  12. using ::asinh;
  13. using ::atanh;
  14. using ::erf;
  15. using ::erfc;
  16. using ::expm1;
  17. using ::lgamma;
  18. using ::log1p;
  19. using ::nearbyint;
  20. using ::round;
  21. using ::tgamma;
  22. using ::trunc;
  23. using ::truncf;
  24. // Define float versions the same way as more recent libstdc++
  25. inline float acosh(float x) {
  26. return __builtin_acoshf(x);
  27. }
  28. inline float asinh(float x) {
  29. return __builtin_asinhf(x);
  30. }
  31. inline float atanh(float x) {
  32. return __builtin_atanhf(x);
  33. }
  34. inline float copysign(float x, float y) {
  35. return __builtin_copysignf(x, y);
  36. }
  37. inline float erf(float x) {
  38. return __builtin_erff(x);
  39. }
  40. inline float erfc(float x) {
  41. return __builtin_erfcf(x);
  42. }
  43. inline float expm1(float x) {
  44. return __builtin_expm1f(x);
  45. }
  46. inline float fmax(float x, float y) {
  47. return __builtin_fmaxf(x, y);
  48. }
  49. inline float fmin(float x, float y) {
  50. return __builtin_fminf(x, y);
  51. }
  52. inline float lgamma(float x) {
  53. return __builtin_lgammaf(x);
  54. }
  55. inline float log1p(float x) {
  56. return __builtin_log1pf(x);
  57. }
  58. inline float nearbyint(float x) {
  59. return __builtin_nearbyintf(x);
  60. }
  61. inline float remainder(float x, float y) {
  62. return __builtin_remainderf(x, y);
  63. }
  64. inline float round(float x) {
  65. return __builtin_roundf(x);
  66. }
  67. inline float tgamma(float x) {
  68. return __builtin_tgammaf(x);
  69. }
  70. inline float trunc(float x) {
  71. return __builtin_truncf(x);
  72. }
  73. // __builtin_nexttoward isn't doesn't work. It appears to try to
  74. // link against the global nexttoward function, which is not present
  75. // prior to API 18. Just bail for now.
  76. inline float nexttoward(float x, long double y) {
  77. throw std::runtime_error("std::nexttoward is not present on older Android");
  78. }
  79. inline double nexttoward(double x, long double y) {
  80. throw std::runtime_error("std::nexttoward is not present on older Android");
  81. }
  82. #if !defined(__NEWLIB__)
  83. // TODO: this function needs to be implemented and tested. Currently just throw
  84. // an error.
  85. inline float hypot(float x, float y) {
  86. throw std::runtime_error("std::hypot is not implemented on older Android");
  87. }
  88. inline double hypot(double x, double y) {
  89. throw std::runtime_error("std::hypot is not implemented on older Android");
  90. }
  91. #else
  92. inline float hypot(float x, float y) {
  93. return hypot((double)x, (double)y);
  94. }
  95. #endif
  96. // TODO: this function needs to be implemented and tested. Currently just throw
  97. // an error.
  98. inline float igamma(float x, float y) {
  99. throw std::runtime_error("igamma is not implemented on older Android");
  100. }
  101. inline double igamma(double x, double y) {
  102. throw std::runtime_error("igamma is not implemented on older Android");
  103. }
  104. inline float igammac(float x, float y) {
  105. throw std::runtime_error("igammac is not implemented on older Android");
  106. }
  107. inline double igammac(double x, double y) {
  108. throw std::runtime_error("igammac is not implemented on older Android");
  109. }
  110. // Note: std::signbit returns true for negative zero (-0), but this
  111. // implementation returns false.
  112. inline bool signbit(float x) {
  113. return x < 0;
  114. }
  115. inline bool signbit(double x) {
  116. return x < 0;
  117. }
  118. inline bool signbit(long double x) {
  119. return x < 0;
  120. }
  121. #if !defined(__NEWLIB__)
  122. // TODO: this function needs to be implemented and tested. Currently just throw
  123. // an error.
  124. inline float nextafter(float x, float y) {
  125. throw std::runtime_error(
  126. "std::nextafter is not implemented on older Android");
  127. }
  128. inline double nextafter(double x, double y) {
  129. throw std::runtime_error(
  130. "std::nextafter is not implemented on older Android");
  131. }
  132. #else
  133. inline float nextafter(float x, float y) {
  134. return nextafter((double)x, (double)y);
  135. }
  136. #endif
  137. #if !defined(__NEWLIB__)
  138. // TODO: this function needs to be implemented and tested. Currently just throw
  139. // an error.
  140. inline float exp2(float x) {
  141. throw std::runtime_error("std::exp2 is not implemented on older Android");
  142. }
  143. inline double exp2(double x) {
  144. throw std::runtime_error("std::exp2 is not implemented on older Android");
  145. }
  146. #else
  147. inline float exp2(float x) {
  148. return exp2((double)x);
  149. }
  150. #endif
  151. // Define integral versions the same way as more recent libstdc++
  152. template <typename T>
  153. typename std::enable_if<std::is_integral<T>::value, double>::type acosh(T x) {
  154. return __builtin_acosh(x);
  155. }
  156. template <typename T>
  157. typename std::enable_if<std::is_integral<T>::value, double>::type asinh(T x) {
  158. return __builtin_asinh(x);
  159. }
  160. template <typename T>
  161. typename std::enable_if<std::is_integral<T>::value, double>::type atanh(T x) {
  162. return __builtin_atanh(x);
  163. }
  164. template <typename T>
  165. typename std::enable_if<std::is_integral<T>::value, double>::type erf(T x) {
  166. return __builtin_erf(x);
  167. }
  168. template <typename T>
  169. typename std::enable_if<std::is_integral<T>::value, double>::type erfc(T x) {
  170. return __builtin_erfc(x);
  171. }
  172. template <typename T>
  173. typename std::enable_if<std::is_integral<T>::value, double>::type expm1(T x) {
  174. return __builtin_expm1(x);
  175. }
  176. template <typename T>
  177. typename std::enable_if<std::is_integral<T>::value, double>::type lgamma(T x) {
  178. return __builtin_lgamma(x);
  179. }
  180. template <typename T>
  181. typename std::enable_if<std::is_integral<T>::value, double>::type log1p(T x) {
  182. return __builtin_log1p(x);
  183. }
  184. template <typename T>
  185. typename std::enable_if<std::is_integral<T>::value, double>::type nearbyint(
  186. T x) {
  187. return __builtin_nearbyint(x);
  188. }
  189. template <typename T>
  190. typename std::enable_if<std::is_integral<T>::value, double>::type round(T x) {
  191. return __builtin_round(x);
  192. }
  193. template <typename T>
  194. typename std::enable_if<std::is_integral<T>::value, double>::type tgamma(T x) {
  195. return __builtin_tgamma(x);
  196. }
  197. template <typename T>
  198. typename std::enable_if<std::is_integral<T>::value, double>::type trunc(T x) {
  199. return __builtin_trunc(x);
  200. }
  201. // Convoluted definition of these binary functions for overloads other than
  202. // (float,float) and (double,double). Using a template from __gnu_cxx
  203. // is dirty, but this code is only enabled on a dead platform, so there
  204. // shouldn't be any risk of it breaking due to updates.
  205. template <typename T, typename U>
  206. typename __gnu_cxx::__promote_2<T, U>::__type fmax(T x, U y) {
  207. typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
  208. return fmax(type(x), type(y));
  209. }
  210. template <typename T, typename U>
  211. typename __gnu_cxx::__promote_2<T, U>::__type fmin(T x, U y) {
  212. typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
  213. return fmin(type(x), type(y));
  214. }
  215. template <typename T, typename U>
  216. typename __gnu_cxx::__promote_2<T, U>::__type copysign(T x, U y) {
  217. typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
  218. return copysign(type(x), type(y));
  219. }
  220. template <typename T, typename U>
  221. typename __gnu_cxx::__promote_2<T, U>::__type remainder(T x, U y) {
  222. typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
  223. return remainder(type(x), type(y));
  224. }
  225. // log2 is a macro on Android API < 21, so we need to define it ourselves.
  226. inline float log2(float arg) {
  227. return ::log(arg) / ::log(2.0);
  228. }
  229. #if !defined(__NEWLIB__)
  230. inline double log2(double arg) {
  231. return ::log(arg) / ::log(2.0);
  232. }
  233. #endif
  234. inline long double log2(long double arg) {
  235. return ::log(arg) / ::log(2.0);
  236. }
  237. template <typename T>
  238. typename std::enable_if<std::is_integral<T>::value, double>::type log2(T x) {
  239. return ::log(x) / ::log(2.0);
  240. }
  241. } // namespace std
  242. #endif