Tor  0.4.7.0-alpha-dev
fp.c
Go to the documentation of this file.
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 }
double tor_mathlog(double d)
Definition: fp.c:22
long tor_lround(double d)
Definition: fp.c:31
int64_t clamp_double_to_int64(double number)
Definition: fp.c:61
int64_t tor_llround(double d)
Definition: fp.c:46
Header for fp.c.