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