aboutsummaryrefslogtreecommitdiff
path: root/src/lib/math/fp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/math/fp.c')
-rw-r--r--src/lib/math/fp.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c
new file mode 100644
index 0000000000..d5989db637
--- /dev/null
+++ b/src/lib/math/fp.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2003, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file fp.c
+ *
+ * \brief Basic floating-point compatibility and convenience code.
+ **/
+
+#include "orconfig.h"
+#include "lib/math/fp.h"
+
+#include <math.h>
+
+/**
+ * Returns the natural logarithm of d base e. We defined this wrapper here so
+ * to avoid conflicts with old versions of tor_log(), which were named log().
+ */
+double
+tor_mathlog(double d)
+{
+ return log(d);
+}
+
+/** Return the long integer closest to <b>d</b>. We define this wrapper
+ * here so that not all users of math.h need to use the right incantations
+ * to get the c99 functions. */
+long
+tor_lround(double d)
+{
+#if defined(HAVE_LROUND)
+ return lround(d);
+#elif defined(HAVE_RINT)
+ return (long)rint(d);
+#else
+ return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5));
+#endif /* defined(HAVE_LROUND) || ... */
+}
+
+/** Return the 64-bit integer closest to d. We define this wrapper here so
+ * that not all users of math.h need to use the right incantations to get the
+ * c99 functions. */
+int64_t
+tor_llround(double d)
+{
+#if defined(HAVE_LLROUND)
+ return (int64_t)llround(d);
+#elif defined(HAVE_RINT)
+ return (int64_t)rint(d);
+#else
+ return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5));
+#endif /* defined(HAVE_LLROUND) || ... */
+}
+
+/** Cast a given double value to a int64_t. Return 0 if number is NaN.
+ * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t
+ * range. */
+int64_t
+clamp_double_to_int64(double number)
+{
+ int exponent;
+
+#if defined(MINGW_ANY) && GCC_VERSION >= 409
+/*
+ Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare
+ isnan, isfinite, and signbit. But as implemented in at least some
+ versions of gcc, __builtin_choose_expr() can generate type warnings
+ even from branches that are not taken. So, suppress those warnings.
+*/
+#define PROBLEMATIC_FLOAT_CONVERSION_WARNING
+DISABLE_GCC_WARNING(float-conversion)
+#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */
+
+/*
+ With clang 4.0 we apparently run into "double promotion" warnings here,
+ since clang thinks we're promoting a double to a long double.
+ */
+#if defined(__clang__)
+#if __has_warning("-Wdouble-promotion")
+#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING
+DISABLE_GCC_WARNING(double-promotion)
+#endif
+#endif /* defined(__clang__) */
+
+ /* NaN is a special case that can't be used with the logic below. */
+ if (isnan(number)) {
+ return 0;
+ }
+
+ /* Time to validate if result can overflows a int64_t value. Fun with
+ * float! Find that exponent exp such that
+ * number == x * 2^exp
+ * for some x with abs(x) in [0.5, 1.0). Note that this implies that the
+ * magnitude of number is strictly less than 2^exp.
+ *
+ * If number is infinite, the call to frexp is legal but the contents of
+ * are exponent unspecified. */
+ frexp(number, &exponent);
+
+ /* If the magnitude of number is strictly less than 2^63, the truncated
+ * version of number is guaranteed to be representable. The only
+ * representable integer for which this is not the case is INT64_MIN, but
+ * it is covered by the logic below. */
+ if (isfinite(number) && exponent <= 63) {
+ return (int64_t)number;
+ }
+
+ /* Handle infinities and finite numbers with magnitude >= 2^63. */
+ return signbit(number) ? INT64_MIN : INT64_MAX;
+
+#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING
+ENABLE_GCC_WARNING(double-promotion)
+#endif
+#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING
+ENABLE_GCC_WARNING(float-conversion)
+#endif
+}