pbpt
Loading...
Searching...
No Matches
function.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "math/global.hpp"
4#include <cmath>
5#include <stdexcept>
6#include <type_traits>
7
11#ifndef M_PI
12#define M_PI 3.14159265358979323846
13#endif
14
24
28namespace pbpt::math {
33namespace detail {
34
46template<typename T>
47constexpr T sqrt_newton_raphson(T x, T curr, T prev) {
48 if (curr == prev) {
49 return curr;
50 }
51 // Avoid division by zero if the initial guess is bad, though the public `sqrt` handles x=0.
52 if (curr == 0) {
53 return 0;
54 }
55 T next = 0.5 * (curr + x / curr);
56 return sqrt_newton_raphson(x, next, curr);
57}
58
59
60// ... 已有的 sqrt_newton_raphson ...
61
70template <typename T>
71constexpr T sin_taylor(T x) {
72 // Taylor series for sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ...
73 // We use a limited number of terms for a balance of precision and compile time.
74 T result = x;
75 T power = x;
76 long double fact = 1.0; // Use long double for factorial to maintain precision
77
78 for (int i = 1; i < 10; ++i) { // 10 terms is a good trade-off
79 power *= x * x; // From x^1 to x^3, x^3 to x^5, etc.
80 fact *= (2 * i) * (2 * i + 1); // From 1! to 3!, 3! to 5!, etc.
81
82 if (i % 2 == 1) {
83 result -= power / fact; // Subtraction for x^3, x^7, etc.
84 } else {
85 result += power / fact; // Addition for x^5, x^9, etc.
86 }
87 }
88 return result;
89}
90
99template <typename T>
100constexpr T cos_taylor(T x) {
101 // Taylor series for cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! + ...
102 T result = 1.0;
103 T power = 1.0;
104 long double fact = 1.0;
105
106 for (int i = 1; i < 10; ++i) {
107 power *= x * x; // From x^0 to x^2, x^2 to x^4, etc.
108 fact *= (2 * i - 1) * (2 * i); // From 1 to 2!, 2! to 4!, etc.
109
110 if (i % 2 == 1) {
111 result -= power / fact; // Subtraction for x^2, x^6, etc.
112 } else {
113 result += power / fact; // Addition for x^4, x^8, etc.
114 }
115 }
116 return result;
117}
118
119} // namespace detail
120
127template<typename T>
128constexpr T abs(T x) {
129 if (x < 0) {
130 return -x;
131 }
132 return x;
133}
134
142template <typename T>
143requires std::is_floating_point_v<T>
144constexpr T rad2deg(T rad) {
145 return rad * 180.0 / M_PI;
146}
147
154template <typename T>
155requires std::is_floating_point_v<T>
156constexpr T deg2rad(T deg) {
157 return deg * M_PI / 180.0;
158}
159
176template<typename T>
177constexpr T sqrt(T x) {
178 // Handle negative input, which is invalid for real square roots.
179 if (x < 0) {
180 if (std::is_constant_evaluated()) {
181 // Triggers a descriptive compile-time error.
182 throw "Compile-time error: sqrt of negative number";
183 } else {
184 // Throws a standard exception at runtime.
185 // Returning std::sqrt(x) would produce a quiet NaN, which can be harder to debug.
186 throw std::runtime_error("sqrt of negative number");
187 }
188 }
189
190 // Handle zero separately to avoid potential division-by-zero in Newton's method.
191 if (x == 0) {
192 return 0;
193 }
194
195 // Choose the implementation based on the context.
196 if (std::is_constant_evaluated()) {
197 // Compile-time context: call our custom constexpr implementation.
198 // We start with an initial guess of x itself.
199 return detail::sqrt_newton_raphson(x, x, T(0));
200 } else {
201 // Runtime context: call the highly optimized standard library function.
202 return std::sqrt(x);
203 }
204}
205
214template <typename T>
215requires std::is_floating_point_v<T>
216constexpr T sin(T x) {
217 if (std::is_constant_evaluated()) {
218 constexpr T pi = T(M_PI);
219 constexpr T two_pi = 2 * pi;
220
221 // Manual fmod to bring angle into [-2*PI, 2*PI] range
222 T reduced_x = x;
223 while (reduced_x > two_pi) { reduced_x -= two_pi; }
224 while (reduced_x < -two_pi) { reduced_x += two_pi; }
225
226 // Use trigonometric identities to map the angle to [0, PI/2] for best Taylor precision
227 if (reduced_x < 0) {
228 return -sin(-reduced_x); // sin(-x) = -sin(x)
229 }
230 if (reduced_x > pi) {
231 return -sin(reduced_x - pi); // sin(x) = -sin(x-pi) for x > pi
232 }
233 if (reduced_x > pi / 2) {
234 return sin(pi - reduced_x); // sin(x) = sin(pi-x) for x > pi/2
235 }
236 return detail::sin_taylor(reduced_x);
237 } else {
238 return std::sin(x);
239 }
240}
241
250template <typename T>
251requires std::is_floating_point_v<T>
252constexpr T cos(T x) {
253 if (std::is_constant_evaluated()) {
254 // Use the identity cos(x) = sin(x + PI/2)
255 return sin(x + T(M_PI) / 2.0);
256 } else {
257 return std::cos(x);
258 }
259}
260
269template <typename T>
270requires std::is_floating_point_v<T>
271constexpr T tan(T x) {
272 return sin(x) / cos(x);
273}
274
285template <typename T>
286requires std::is_floating_point_v<T>
287constexpr bool is_equal(T a, T b) {
288 return abs(a - b) < EPSILON;
289}
290
299template <typename T>
300requires std::is_floating_point_v<T>
301constexpr bool is_greater(T a, T b) {
302 return a - b > EPSILON;
303}
304
313template <typename T>
314requires std::is_floating_point_v<T>
315constexpr bool is_less_equal(T a, T b) {
316 return !is_greater(a, b);
317}
318
327template <typename T>
328requires std::is_floating_point_v<T>
329constexpr bool is_less(T a, T b) {
330 return b - a > EPSILON;
331}
332
341template <typename T>
342requires std::is_floating_point_v<T>
343constexpr bool is_greater_equal(T a, T b) {
344 return !is_less(a, b);
345}
346
347} // namespace math
#define M_PI
Define _USE_MATH_DEFINES for M_PI on MSVC, or just define pi ourselves for portability.
Definition function.hpp:12
Defines the primary floating-point type alias for the math library.
#define EPSILON
The epsilon value used for floating-point comparisons.
Definition global.hpp:41
Contains internal implementation details for the math library.
Definition function.hpp:33
constexpr T sqrt_newton_raphson(T x, T curr, T prev)
A constexpr implementation of the square root function using the Newton-Raphson method.
Definition function.hpp:47
constexpr T sin_taylor(T x)
A constexpr implementation of the sine function using a Taylor series expansion.
Definition function.hpp:71
constexpr T cos_taylor(T x)
A constexpr implementation of the cosine function using a Taylor series expansion.
Definition function.hpp:100
The namespace for math library implementation.
Definition bounding_box.hpp:9
constexpr T rad2deg(T rad)
Converts an angle from radians to degrees.
Definition function.hpp:144
constexpr T deg2rad(T deg)
Converts an angle from degrees to radians.
Definition function.hpp:156
constexpr T sqrt(T x)
Calculates the square root of a number with constexpr support.
Definition function.hpp:177
constexpr bool is_greater_equal(T a, T b)
Compares if a is greater than or equal to b.
Definition function.hpp:343
constexpr bool is_greater(T a, T b)
Compares if a is greater than b.
Definition function.hpp:301
constexpr T cos(T x)
Calculates the cosine of an angle with constexpr support.
Definition function.hpp:252
constexpr T abs(T x)
A constexpr implementation of the absolute value function.
Definition function.hpp:128
constexpr bool is_less_equal(T a, T b)
Compares if a is less than or equal to b.
Definition function.hpp:315
constexpr bool is_equal(T a, T b)
Compares two floating-point values for equality.
Definition function.hpp:287
constexpr T sin(T x)
Calculates the sine of an angle with constexpr support.
Definition function.hpp:216
constexpr bool is_less(T a, T b)
Compares if a is less than b.
Definition function.hpp:329
constexpr T tan(T x)
Calculates the tangent of an angle with constexpr support.
Definition function.hpp:271