fp.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /* Copyright (c) 2003, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file fp.c
  7. *
  8. * \brief Basic floating-point compatibility and convenience code.
  9. **/
  10. #include "orconfig.h"
  11. #include "lib/math/fp.h"
  12. #include <math.h>
  13. /**
  14. * Returns the natural logarithm of d base e. We defined this wrapper here so
  15. * to avoid conflicts with old versions of tor_log(), which were named log().
  16. */
  17. double
  18. tor_mathlog(double d)
  19. {
  20. return log(d);
  21. }
  22. /** Return the long integer closest to <b>d</b>. We define this wrapper
  23. * here so that not all users of math.h need to use the right incantations
  24. * to get the c99 functions. */
  25. long
  26. tor_lround(double d)
  27. {
  28. #if defined(HAVE_LROUND)
  29. return lround(d);
  30. #elif defined(HAVE_RINT)
  31. return (long)rint(d);
  32. #else
  33. return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5));
  34. #endif /* defined(HAVE_LROUND) || ... */
  35. }
  36. /** Return the 64-bit integer closest to d. We define this wrapper here so
  37. * that not all users of math.h need to use the right incantations to get the
  38. * c99 functions. */
  39. int64_t
  40. tor_llround(double d)
  41. {
  42. #if defined(HAVE_LLROUND)
  43. return (int64_t)llround(d);
  44. #elif defined(HAVE_RINT)
  45. return (int64_t)rint(d);
  46. #else
  47. return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5));
  48. #endif /* defined(HAVE_LLROUND) || ... */
  49. }
  50. /** Cast a given double value to a int64_t. Return 0 if number is NaN.
  51. * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t
  52. * range. */
  53. int64_t
  54. clamp_double_to_int64(double number)
  55. {
  56. int exponent;
  57. #if (defined(MINGW_ANY)||defined(__FreeBSD__)) && GCC_VERSION >= 409
  58. /*
  59. Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare
  60. isnan, isfinite, and signbit. But as implemented in at least some
  61. versions of gcc, __builtin_choose_expr() can generate type warnings
  62. even from branches that are not taken. So, suppress those warnings.
  63. FreeBSD's math.h uses an __fp_type_select() macro, which dispatches
  64. based on sizeof -- again, this can generate type warnings from
  65. branches that are not taken.
  66. */
  67. #define PROBLEMATIC_FLOAT_CONVERSION_WARNING
  68. DISABLE_GCC_WARNING(float-conversion)
  69. #endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */
  70. /*
  71. With clang 4.0 we apparently run into "double promotion" warnings here,
  72. since clang thinks we're promoting a double to a long double.
  73. */
  74. #if defined(__clang__)
  75. #if __has_warning("-Wdouble-promotion")
  76. #define PROBLEMATIC_DOUBLE_PROMOTION_WARNING
  77. DISABLE_GCC_WARNING(double-promotion)
  78. #endif
  79. #endif /* defined(__clang__) */
  80. /* NaN is a special case that can't be used with the logic below. */
  81. if (isnan(number)) {
  82. return 0;
  83. }
  84. /* Time to validate if result can overflows a int64_t value. Fun with
  85. * float! Find that exponent exp such that
  86. * number == x * 2^exp
  87. * for some x with abs(x) in [0.5, 1.0). Note that this implies that the
  88. * magnitude of number is strictly less than 2^exp.
  89. *
  90. * If number is infinite, the call to frexp is legal but the contents of
  91. * are exponent unspecified. */
  92. frexp(number, &exponent);
  93. /* If the magnitude of number is strictly less than 2^63, the truncated
  94. * version of number is guaranteed to be representable. The only
  95. * representable integer for which this is not the case is INT64_MIN, but
  96. * it is covered by the logic below. */
  97. if (isfinite(number) && exponent <= 63) {
  98. return (int64_t)number;
  99. }
  100. /* Handle infinities and finite numbers with magnitude >= 2^63. */
  101. return signbit(number) ? INT64_MIN : INT64_MAX;
  102. #ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
  103. ENABLE_GCC_WARNING(double-promotion)
  104. #endif
  105. #ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
  106. ENABLE_GCC_WARNING(float-conversion)
  107. #endif
  108. }