summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/MathUtils.h
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
committermanuel <manuel@mausz.at>2020-10-19 00:52:24 +0200
commitbe933ef2241d79558f91796cc5b3a161f72ebf9c (patch)
treefe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/utils/MathUtils.h
parent5f8335c1e49ce108ef3481863833c98efa00411b (diff)
downloadkodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.gz
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.tar.bz2
kodi-pvr-build-be933ef2241d79558f91796cc5b3a161f72ebf9c.zip
sync with upstream
Diffstat (limited to 'xbmc/utils/MathUtils.h')
-rw-r--r--xbmc/utils/MathUtils.h215
1 files changed, 215 insertions, 0 deletions
diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h
new file mode 100644
index 0000000..7a69db7
--- /dev/null
+++ b/xbmc/utils/MathUtils.h
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#pragma once
10
11#include <stdint.h>
12#include <assert.h>
13#include <climits>
14#include <cmath>
15
16#if defined(HAVE_SSE2) && defined(__SSE2__)
17#include <emmintrin.h>
18#endif
19
20// use real compiler defines in here as we want to
21// avoid including system.h or other magic includes.
22// use 'gcc -dM -E - < /dev/null' or similar to find them.
23
24#if defined(__ppc__) || \
25 defined(__powerpc__) || \
26 defined(__mips__) || \
27 defined(__arm__) || \
28 defined(__aarch64__) || \
29 defined(__SH4__) || \
30 defined(__sparc__) || \
31 defined(__arc__) || \
32 defined(_M_ARM) || \
33 defined(__or1k__) || \
34 defined(__xtensa__)
35 #define DISABLE_MATHUTILS_ASM_ROUND_INT
36#endif
37
38/*! \brief Math utility class.
39 Note that the test() routine should return true for all implementations
40
41 See http://ldesoras.free.fr/doc/articles/rounding_en.pdf for an explanation
42 of the technique used on x86.
43 */
44namespace MathUtils
45{
46 // GCC does something stupid with optimization on release builds if we try
47 // to assert in these functions
48
49 /*! \brief Round to nearest integer.
50 This routine does fast rounding to the nearest integer.
51 In the case (k + 0.5 for any integer k) we round up to k+1, and in all other
52 instances we should return the nearest integer.
53 Thus, { -1.5, -0.5, 0.5, 1.5 } is rounded to { -1, 0, 1, 2 }.
54 It preserves the property that round(k) - round(k-1) = 1 for all doubles k.
55
56 Make sure MathUtils::test() returns true for each implementation.
57 \sa truncate_int, test
58 */
59 inline int round_int(double x)
60 {
61 assert(x > static_cast<double>((int) (INT_MIN / 2)) - 1.0);
62 assert(x < static_cast<double>((int) (INT_MAX / 2)) + 1.0);
63
64#if defined(DISABLE_MATHUTILS_ASM_ROUND_INT)
65 /* This implementation warrants some further explanation.
66 *
67 * First, a couple of notes on rounding:
68 * 1) C casts from float/double to integer round towards zero.
69 * 2) Float/double additions are rounded according to the normal rules,
70 * in other words: on some architectures, it's fixed at compile-time,
71 * and on others it can be set using fesetround()). The following
72 * analysis assumes round-to-nearest with ties rounding to even. This
73 * is a fairly sensible choice, and is the default with ARM VFP.
74 *
75 * What this function wants is round-to-nearest with ties rounding to
76 * +infinity. This isn't an IEEE rounding mode, even if we could guarantee
77 * that all architectures supported fesetround(), which they don't. Instead,
78 * this adds an offset of 2147483648.5 (= 0x80000000.8p0), then casts to
79 * an unsigned int (crucially, all possible inputs are now in a range where
80 * round to zero acts the same as round to -infinity) and then subtracts
81 * 0x80000000 in the integer domain. The 0.5 component of the offset
82 * converts what is effectively a round down into a round to nearest, with
83 * ties rounding up, as desired.
84 *
85 * There is a catch, that because there is a double rounding, there is a
86 * small region where the input falls just *below* a tie, where the addition
87 * of the offset causes a round *up* to an exact integer, due to the finite
88 * level of precision available in floating point. You need to be aware of
89 * this when calling this function, although at present it is not believed
90 * that XBMC ever attempts to round numbers in this window.
91 *
92 * It is worth proving the size of the affected window. Recall that double
93 * precision employs a mantissa of 52 bits.
94 * 1) For all inputs -0.5 <= x <= INT_MAX
95 * Once the offset is applied, the most significant binary digit in the
96 * floating-point representation is +2^31.
97 * At this magnitude, the smallest step representable in double precision
98 * is 2^31 / 2^52 = 0.000000476837158203125
99 * So the size of the range which is rounded up due to the addition is
100 * half the size of this step, or 0.0000002384185791015625
101 *
102 * 2) For all inputs INT_MIN/2 < x < -0.5
103 * Once the offset is applied, the most significant binary digit in the
104 * floating-point representation is +2^30.
105 * At this magnitude, the smallest step representable in double precision
106 * is 2^30 / 2^52 = 0.0000002384185791015625
107 * So the size of the range which is rounded up due to the addition is
108 * half the size of this step, or 0.00000011920928955078125
109 *
110 * 3) For all inputs INT_MIN <= x <= INT_MIN/2
111 * The representation once the offset is applied has equal or greater
112 * precision than the input, so the addition does not cause rounding.
113 */
114 return ((unsigned int) (x + 2147483648.5)) - 0x80000000;
115
116#else
117 const float round_to_nearest = 0.5f;
118 int i;
119#if defined(HAVE_SSE2) && defined(__SSE2__)
120 const float round_dn_to_nearest = 0.4999999f;
121 i = (x > 0) ? _mm_cvttsd_si32(_mm_set_sd(x + round_to_nearest)) : _mm_cvttsd_si32(_mm_set_sd(x - round_dn_to_nearest));
122
123#elif defined(TARGET_WINDOWS)
124 __asm
125 {
126 fld x
127 fadd st, st (0)
128 fadd round_to_nearest
129 fistp i
130 sar i, 1
131 }
132
133#else
134 __asm__ __volatile__ (
135 "fadd %%st\n\t"
136 "fadd %%st(1)\n\t"
137 "fistpl %0\n\t"
138 "sarl $1, %0\n"
139 : "=m"(i) : "u"(round_to_nearest), "t"(x) : "st"
140 );
141
142#endif
143 return i;
144#endif
145 }
146
147 /*! \brief Truncate to nearest integer.
148 This routine does fast truncation to an integer.
149 It should simply drop the fractional portion of the floating point number.
150
151 Make sure MathUtils::test() returns true for each implementation.
152 \sa round_int, test
153 */
154 inline int truncate_int(double x)
155 {
156 assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
157 assert(x < static_cast<double>(INT_MAX / 2) + 1.0);
158 return static_cast<int>(x);
159 }
160
161 inline int64_t abs(int64_t a)
162 {
163 return (a < 0) ? -a : a;
164 }
165
166 inline unsigned bitcount(unsigned v)
167 {
168 unsigned c = 0;
169 for (c = 0; v; c++)
170 v &= v - 1; // clear the least significant bit set
171 return c;
172 }
173
174 inline void hack()
175 {
176 // stupid hack to keep compiler from dropping these
177 // functions as unused
178 MathUtils::round_int(0.0);
179 MathUtils::truncate_int(0.0);
180 MathUtils::abs(0);
181 }
182
183 /**
184 * Compare two floating-point numbers for equality and regard them
185 * as equal if their difference is below a given threshold.
186 *
187 * It is usually not useful to compare float numbers for equality with
188 * the standard operator== since very close numbers might have different
189 * representations.
190 */
191 template<typename FloatT>
192 inline bool FloatEquals(FloatT f1, FloatT f2, FloatT maxDelta)
193 {
194 return (std::abs(f2 - f1) < maxDelta);
195 }
196
197#if 0
198 /*! \brief test routine for round_int and truncate_int
199 Must return true on all platforms.
200 */
201 inline bool test()
202 {
203 for (int i = -8; i < 8; ++i)
204 {
205 double d = 0.25*i;
206 int r = (i < 0) ? (i - 1) / 4 : (i + 2) / 4;
207 int t = i / 4;
208 if (round_int(d) != r || truncate_int(d) != t)
209 return false;
210 }
211 return true;
212 }
213#endif
214} // namespace MathUtils
215