mono-math.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * \file
  3. */
  4. #ifndef __MONO_MATH_H__
  5. #define __MONO_MATH_H__
  6. #include <math.h>
  7. #include <mono/utils/mono-publib.h>
  8. // Instead of isfinite, isinf, isnan, etc.,
  9. // use mono_isfininite, mono_isinf, mono_isnan, etc.
  10. // These functions are implemented in C in order to avoid
  11. // a C++ runtime dependency and for more portable binding
  12. // from C++, esp. across Android versions/architectures.
  13. // WebAssembly, and Win32/gcc.
  14. // See https://github.com/mono/mono/pull/10701 for what
  15. // this systematically and more portably cleans up.
  16. #if defined (__cplusplus) || defined (MONO_MATH_DECLARE_ALL)
  17. // These declarations are usually hidden, in order
  18. // to encourage using the overloaded names instead of
  19. // the type-specific names.
  20. G_EXTERN_C int mono_isfinite_float (float);
  21. G_EXTERN_C int mono_isfinite_double (double);
  22. G_EXTERN_C int mono_isinf_float (float);
  23. G_EXTERN_C int mono_isinf_double (double);
  24. G_EXTERN_C int mono_isnan_float (float);
  25. G_EXTERN_C int mono_isnan_double (double);
  26. G_EXTERN_C int mono_isunordered_float (float, float);
  27. G_EXTERN_C int mono_isunordered_double (double, double);
  28. G_EXTERN_C int mono_signbit_float (float a);
  29. G_EXTERN_C int mono_signbit_double (double a);
  30. G_EXTERN_C float mono_trunc_float (float);
  31. G_EXTERN_C double mono_trunc_double (double);
  32. #endif
  33. #ifdef __cplusplus
  34. // There are three or four possible approaches here.
  35. // 1. C++ mono_foo => foo
  36. // 2. C++ mono_foo => std::foo
  37. // 3. C++ mono_foo => C mono_foo_[float,double] => C foo
  38. // 4. using std::foo -- this works mostly but not quite -- it doesn't
  39. // work when there is already a global foo.
  40. //
  41. // Approach 1 works on non-wasm, non-android non-Win32/gcc.
  42. // Approach 2 should work everywhere, but might incur a new dependency, might.
  43. // Approach 3 should work everywhere, with identical dependencies as mono/C.
  44. // This is approach 3.
  45. // Approach 4 lets code keep calling foo instead of mono_foo.
  46. // Approaches 1, 2, 4 are most efficient. 1, 2 require inlining, 4 does not.
  47. inline int mono_isfinite (float a) { return mono_isfinite_float (a); }
  48. inline int mono_isfinite (double a) { return mono_isfinite_double (a); }
  49. inline int mono_isinf (float a) { return mono_isinf_float (a); }
  50. inline int mono_isinf (double a) { return mono_isinf_double (a); }
  51. inline int mono_isnan (float a) { return mono_isnan_float (a); }
  52. inline int mono_isnan (double a) { return mono_isnan_double (a); }
  53. inline int mono_isunordered (float a, float b) { return mono_isunordered_float (a, b); }
  54. inline int mono_isunordered (double a, double b) { return mono_isunordered_double (a, b); }
  55. inline int mono_signbit (float a) { return mono_signbit_float (a); }
  56. inline int mono_signbit (double a) { return mono_signbit_double (a); }
  57. inline float mono_trunc (float a) { return mono_trunc_float (a); }
  58. inline double mono_trunc (double a) { return mono_trunc_double (a); }
  59. #else
  60. // Direct macros for C.
  61. // This will also work for many C++ platforms, i.e. other than Android and WebAssembly and Win32/gcc.
  62. #define mono_isfinite isfinite
  63. #define mono_isinf isinf
  64. #define mono_isnan isnan
  65. #define mono_isunordered isunordered
  66. #define mono_signbit signbit
  67. #define mono_trunc trunc
  68. #endif
  69. static inline double
  70. mono_round_to_even (double x)
  71. {
  72. double floor_tmp;
  73. /* If the number has no fractional part do nothing This shortcut is necessary
  74. * to workaround precision loss in borderline cases on some platforms */
  75. if (x == (double)(int64_t) x)
  76. return x;
  77. floor_tmp = floor (x + 0.5);
  78. if ((x == (floor (x) + 0.5)) && (fmod (floor_tmp, 2.0) != 0)) {
  79. floor_tmp -= 1.0;
  80. }
  81. return copysign (floor_tmp, x);
  82. }
  83. #endif