Line data Source code
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 1143 : tor_mathlog(double d) 23 : { 24 1143 : 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 5124 : 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 5124 : 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 231147 : 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 231147 : 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 59 : clamp_double_to_int64(double number) 62 : { 63 59 : 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 59 : 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 58 : 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 58 : if (isfinite(number) && exponent <= 63) { 111 47 : return (int64_t)number; 112 : } 113 : 114 : /* Handle infinities and finite numbers with magnitude >= 2^63. */ 115 11 : 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 10891 : 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 10891 : 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 : }