diff options
| author | manuel <manuel@mausz.at> | 2020-10-19 00:52:24 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2020-10-19 00:52:24 +0200 |
| commit | be933ef2241d79558f91796cc5b3a161f72ebf9c (patch) | |
| tree | fe3ab2f130e20c99001f2d7a81d610c78c96a3f4 /xbmc/utils/MathUtils.h | |
| parent | 5f8335c1e49ce108ef3481863833c98efa00411b (diff) | |
| download | kodi-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.h | 215 |
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 | */ | ||
| 44 | namespace 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 | |||
