Tor 0.4.9.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 */
21double
22tor_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. */
30long
31tor_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. */
45int64_t
46tor_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. */
60int64_t
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
77DISABLE_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
87DISABLE_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
118ENABLE_GCC_WARNING("-Wdouble-promotion")
119#endif
120#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
121ENABLE_GCC_WARNING("-Wfloat-conversion")
122#endif
123}
124
125/* isinf() wrapper for tor */
126int
127tor_isinf(double x)
128{
129 /* Same as above, work around the "double promotion" warnings */
130#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
131DISABLE_GCC_WARNING("-Wfloat-conversion")
132#endif
133#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
134DISABLE_GCC_WARNING("-Wdouble-promotion")
135#endif
136 return isinf(x);
137#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
138ENABLE_GCC_WARNING("-Wdouble-promotion")
139#endif
140#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
141ENABLE_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.