1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QMATH_H |
5 | #define QMATH_H |
6 | |
7 | #if 0 |
8 | #pragma qt_class(QtMath) |
9 | #endif |
10 | |
11 | #include <QtCore/qglobal.h> |
12 | #include <QtCore/qalgorithms.h> |
13 | |
14 | #if __has_include(<bit>) && __cplusplus > 201703L |
15 | #include <bit> |
16 | #endif |
17 | |
18 | #ifndef _USE_MATH_DEFINES |
19 | # define _USE_MATH_DEFINES |
20 | # define undef_USE_MATH_DEFINES |
21 | #endif |
22 | |
23 | #include <cmath> |
24 | |
25 | #ifdef undef_USE_MATH_DEFINES |
26 | # undef _USE_MATH_DEFINES |
27 | # undef undef_USE_MATH_DEFINES |
28 | #endif |
29 | |
30 | QT_BEGIN_NAMESPACE |
31 | |
32 | #define QT_SINE_TABLE_SIZE 256 |
33 | |
34 | extern Q_CORE_EXPORT const qreal qt_sine_table[QT_SINE_TABLE_SIZE]; |
35 | |
36 | template <typename T> int qCeil(T v) |
37 | { |
38 | using std::ceil; |
39 | return int(ceil(v)); |
40 | } |
41 | |
42 | template <typename T> int qFloor(T v) |
43 | { |
44 | using std::floor; |
45 | return int(floor(v)); |
46 | } |
47 | |
48 | template <typename T> auto qFabs(T v) |
49 | { |
50 | using std::fabs; |
51 | return fabs(v); |
52 | } |
53 | |
54 | template <typename T> auto qSin(T v) |
55 | { |
56 | using std::sin; |
57 | return sin(v); |
58 | } |
59 | |
60 | template <typename T> auto qCos(T v) |
61 | { |
62 | using std::cos; |
63 | return cos(v); |
64 | } |
65 | |
66 | template <typename T> auto qTan(T v) |
67 | { |
68 | using std::tan; |
69 | return tan(v); |
70 | } |
71 | |
72 | template <typename T> auto qAcos(T v) |
73 | { |
74 | using std::acos; |
75 | return acos(v); |
76 | } |
77 | |
78 | template <typename T> auto qAsin(T v) |
79 | { |
80 | using std::asin; |
81 | return asin(v); |
82 | } |
83 | |
84 | template <typename T> auto qAtan(T v) |
85 | { |
86 | using std::atan; |
87 | return atan(v); |
88 | } |
89 | |
90 | template <typename T1, typename T2> auto qAtan2(T1 y, T2 x) |
91 | { |
92 | using std::atan2; |
93 | return atan2(y, x); |
94 | } |
95 | |
96 | template <typename T> auto qSqrt(T v) |
97 | { |
98 | using std::sqrt; |
99 | return sqrt(v); |
100 | } |
101 | |
102 | namespace QtPrivate { |
103 | template <typename R, typename F> // For qfloat16 to specialize |
104 | struct QHypotType { using type = decltype(std::hypot(R(1), F(1))); }; |
105 | |
106 | // Implements hypot() without limiting number of arguments: |
107 | template <typename T> |
108 | class QHypotHelper |
109 | { |
110 | T scale, total; |
111 | template <typename F> friend class QHypotHelper; |
112 | QHypotHelper(T first, T prior) : scale(first), total(prior) {} |
113 | public: |
114 | QHypotHelper(T first) : scale(qAbs(first)), total(1) {} |
115 | T result() const |
116 | { return qIsFinite(scale) ? scale > 0 ? scale * T(qSqrt(total)) : T(0) : scale; } |
117 | |
118 | template<typename F, typename ...Fs> |
119 | auto add(F first, Fs... rest) const |
120 | { return add(first).add(rest...); } |
121 | |
122 | template<typename F, typename R = typename QHypotType<T, F>::type> |
123 | QHypotHelper<R> add(F next) const |
124 | { |
125 | if (qIsInf(scale) || (qIsNaN(scale) && !qIsInf(next))) |
126 | return QHypotHelper<R>(scale, R(1)); |
127 | if (qIsNaN(next)) |
128 | return QHypotHelper<R>(next, R(1)); |
129 | const R val = qAbs(next); |
130 | if (!(scale > 0) || qIsInf(next)) |
131 | return QHypotHelper<R>(val, R(1)); |
132 | if (!(val > 0)) |
133 | return QHypotHelper<R>(scale, total); |
134 | if (val > scale) { |
135 | const R ratio = scale / next; |
136 | return QHypotHelper<R>(val, total * ratio * ratio + R(1)); |
137 | } |
138 | const R ratio = next / scale; |
139 | return QHypotHelper<R>(scale, total + ratio * ratio); |
140 | } |
141 | }; |
142 | } // QtPrivate |
143 | |
144 | template<typename F, typename ...Fs> |
145 | auto qHypot(F first, Fs... rest) |
146 | { |
147 | return QtPrivate::QHypotHelper<F>(first).add(rest...).result(); |
148 | } |
149 | |
150 | // However, where possible, use the standard library implementations: |
151 | template <typename Tx, typename Ty> |
152 | auto qHypot(Tx x, Ty y) |
153 | { |
154 | // C99 has hypot(), hence C++11 has std::hypot() |
155 | using std::hypot; |
156 | return hypot(x, y); |
157 | } |
158 | |
159 | #if defined(__cpp_lib_hypot) && __cpp_lib_hypot >= 201603L // Expected to be true |
160 | template <typename Tx, typename Ty, typename Tz> |
161 | auto qHypot(Tx x, Ty y, Tz z) |
162 | { |
163 | using std::hypot; |
164 | return hypot(x, y, z); |
165 | } |
166 | #endif // else: no need to over-ride the arbitrarily-many-arg form |
167 | |
168 | template <typename T> auto qLn(T v) |
169 | { |
170 | using std::log; |
171 | return log(v); |
172 | } |
173 | |
174 | template <typename T> auto qExp(T v) |
175 | { |
176 | using std::exp; |
177 | return exp(v); |
178 | } |
179 | |
180 | template <typename T1, typename T2> auto qPow(T1 x, T2 y) |
181 | { |
182 | using std::pow; |
183 | return pow(x, y); |
184 | } |
185 | |
186 | // TODO: use template variables (e.g. Qt::pi<type>) for these once we have C++14 support: |
187 | |
188 | #ifndef M_E |
189 | #define M_E (2.7182818284590452354) |
190 | #endif |
191 | |
192 | #ifndef M_LOG2E |
193 | #define M_LOG2E (1.4426950408889634074) |
194 | #endif |
195 | |
196 | #ifndef M_LOG10E |
197 | #define M_LOG10E (0.43429448190325182765) |
198 | #endif |
199 | |
200 | #ifndef M_LN2 |
201 | #define M_LN2 (0.69314718055994530942) |
202 | #endif |
203 | |
204 | #ifndef M_LN10 |
205 | #define M_LN10 (2.30258509299404568402) |
206 | #endif |
207 | |
208 | #ifndef M_PI |
209 | #define M_PI (3.14159265358979323846) |
210 | #endif |
211 | |
212 | #ifndef M_PI_2 |
213 | #define M_PI_2 (1.57079632679489661923) |
214 | #endif |
215 | |
216 | #ifndef M_PI_4 |
217 | #define M_PI_4 (0.78539816339744830962) |
218 | #endif |
219 | |
220 | #ifndef M_1_PI |
221 | #define M_1_PI (0.31830988618379067154) |
222 | #endif |
223 | |
224 | #ifndef M_2_PI |
225 | #define M_2_PI (0.63661977236758134308) |
226 | #endif |
227 | |
228 | #ifndef M_2_SQRTPI |
229 | #define M_2_SQRTPI (1.12837916709551257390) |
230 | #endif |
231 | |
232 | #ifndef M_SQRT2 |
233 | #define M_SQRT2 (1.41421356237309504880) |
234 | #endif |
235 | |
236 | #ifndef M_SQRT1_2 |
237 | #define M_SQRT1_2 (0.70710678118654752440) |
238 | #endif |
239 | |
240 | inline qreal qFastSin(qreal x) |
241 | { |
242 | int si = int(x * (0.5 * QT_SINE_TABLE_SIZE / M_PI)); // Would be more accurate with qRound, but slower. |
243 | qreal d = x - si * (2.0 * M_PI / QT_SINE_TABLE_SIZE); |
244 | int ci = si + QT_SINE_TABLE_SIZE / 4; |
245 | si &= QT_SINE_TABLE_SIZE - 1; |
246 | ci &= QT_SINE_TABLE_SIZE - 1; |
247 | return qt_sine_table[si] + (qt_sine_table[ci] - 0.5 * qt_sine_table[si] * d) * d; |
248 | } |
249 | |
250 | inline qreal qFastCos(qreal x) |
251 | { |
252 | int ci = int(x * (0.5 * QT_SINE_TABLE_SIZE / M_PI)); // Would be more accurate with qRound, but slower. |
253 | qreal d = x - ci * (2.0 * M_PI / QT_SINE_TABLE_SIZE); |
254 | int si = ci + QT_SINE_TABLE_SIZE / 4; |
255 | si &= QT_SINE_TABLE_SIZE - 1; |
256 | ci &= QT_SINE_TABLE_SIZE - 1; |
257 | return qt_sine_table[si] - (qt_sine_table[ci] + 0.5 * qt_sine_table[si] * d) * d; |
258 | } |
259 | |
260 | constexpr inline float qDegreesToRadians(float degrees) |
261 | { |
262 | return degrees * float(M_PI / 180); |
263 | } |
264 | |
265 | constexpr inline double qDegreesToRadians(double degrees) |
266 | { |
267 | return degrees * (M_PI / 180); |
268 | } |
269 | |
270 | constexpr inline long double qDegreesToRadians(long double degrees) |
271 | { |
272 | return degrees * (M_PI / 180); |
273 | } |
274 | |
275 | template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true> |
276 | constexpr inline double qDegreesToRadians(T degrees) |
277 | { |
278 | return qDegreesToRadians(degrees: static_cast<double>(degrees)); |
279 | } |
280 | |
281 | constexpr inline float qRadiansToDegrees(float radians) |
282 | { |
283 | return radians * float(180 / M_PI); |
284 | } |
285 | |
286 | constexpr inline double qRadiansToDegrees(double radians) |
287 | { |
288 | return radians * (180 / M_PI); |
289 | } |
290 | |
291 | constexpr inline long double qRadiansToDegrees(long double radians) |
292 | { |
293 | return radians * (180 / M_PI); |
294 | } |
295 | |
296 | // A qRadiansToDegrees(Integral) overload isn't here; it's extremely |
297 | // questionable that someone is manipulating quantities in radians |
298 | // using integral datatypes... |
299 | |
300 | namespace QtPrivate { |
301 | constexpr inline quint32 qConstexprNextPowerOfTwo(quint32 v) |
302 | { |
303 | v |= v >> 1; |
304 | v |= v >> 2; |
305 | v |= v >> 4; |
306 | v |= v >> 8; |
307 | v |= v >> 16; |
308 | ++v; |
309 | return v; |
310 | } |
311 | |
312 | constexpr inline quint64 qConstexprNextPowerOfTwo(quint64 v) |
313 | { |
314 | v |= v >> 1; |
315 | v |= v >> 2; |
316 | v |= v >> 4; |
317 | v |= v >> 8; |
318 | v |= v >> 16; |
319 | v |= v >> 32; |
320 | ++v; |
321 | return v; |
322 | } |
323 | |
324 | constexpr inline quint32 qConstexprNextPowerOfTwo(qint32 v) |
325 | { |
326 | return qConstexprNextPowerOfTwo(v: quint32(v)); |
327 | } |
328 | |
329 | constexpr inline quint64 qConstexprNextPowerOfTwo(qint64 v) |
330 | { |
331 | return qConstexprNextPowerOfTwo(v: quint64(v)); |
332 | } |
333 | } // namespace QtPrivate |
334 | |
335 | constexpr inline quint32 qNextPowerOfTwo(quint32 v) |
336 | { |
337 | Q_ASSERT(static_cast<qint32>(v) >= 0); // There is a next power of two |
338 | #if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L |
339 | return std::bit_ceil(v + 1); |
340 | #elif defined(QT_HAS_BUILTIN_CLZ) |
341 | if (v == 0) |
342 | return 1; |
343 | return 2U << (31 ^ QAlgorithmsPrivate::qt_builtin_clz(v)); |
344 | #else |
345 | return QtPrivate::qConstexprNextPowerOfTwo(v); |
346 | #endif |
347 | } |
348 | |
349 | constexpr inline quint64 qNextPowerOfTwo(quint64 v) |
350 | { |
351 | Q_ASSERT(static_cast<qint64>(v) >= 0); // There is a next power of two |
352 | #if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L |
353 | return std::bit_ceil(v + 1); |
354 | #elif defined(QT_HAS_BUILTIN_CLZLL) |
355 | if (v == 0) |
356 | return 1; |
357 | return Q_UINT64_C(2) << (63 ^ QAlgorithmsPrivate::qt_builtin_clzll(v)); |
358 | #else |
359 | return QtPrivate::qConstexprNextPowerOfTwo(v); |
360 | #endif |
361 | } |
362 | |
363 | constexpr inline quint32 qNextPowerOfTwo(qint32 v) |
364 | { |
365 | return qNextPowerOfTwo(v: quint32(v)); |
366 | } |
367 | |
368 | constexpr inline quint64 qNextPowerOfTwo(qint64 v) |
369 | { |
370 | return qNextPowerOfTwo(v: quint64(v)); |
371 | } |
372 | |
373 | constexpr inline unsigned long qNextPowerOfTwo(unsigned long v) |
374 | { |
375 | return qNextPowerOfTwo(v: QIntegerForSizeof<long>::Unsigned(v)); |
376 | } |
377 | |
378 | constexpr inline unsigned long qNextPowerOfTwo(long v) |
379 | { |
380 | return qNextPowerOfTwo(v: QIntegerForSizeof<long>::Unsigned(v)); |
381 | } |
382 | |
383 | QT_END_NAMESPACE |
384 | |
385 | #endif // QMATH_H |
386 | |