Photon Common Library 2.0.0-beta
A physically based renderer.
Loading...
Searching...
No Matches
math_basics.h
Go to the documentation of this file.
1#pragma once
2
8#include "Common/assertion.h"
9
10#include <type_traits>
11#include <bit>
12#include <concepts>
13#include <limits>
14
15namespace ph::math
16{
17
20template<typename T>
21inline constexpr bool is_power_of_2(const T value)
22{
23 if constexpr(std::is_unsigned_v<T>)
24 {
25 // STL has this function for unsigned types only
26 return std::has_single_bit(value);
27 }
28 else
29 {
30 return (value > 0) && !(value & (value - 1));
31 }
32}
33
37template<std::size_t BASE, typename T>
38inline constexpr bool is_power_of(const T value)
39{
40 if constexpr(BASE == 0)
41 {
42 return value == 0;
43 }
44 else if constexpr(BASE == 1)
45 {
46 return value == 1;
47 }
48 else if constexpr(BASE == 2)
49 {
50 return is_power_of_2(value);
51 }
52 else
53 {
54 if(value > 0)
55 {
56 static_assert(BASE <= std::numeric_limits<T>::max());
57
58 T powVal = 1;
59 while(powVal < value)
60 {
61 powVal *= static_cast<T>(BASE);// TODO: overflow check
62 }
63
64 return powVal == value;
65 }
66 else
67 {
68 return false;
69 }
70 }
71}
72
76template<std::integral T>
77inline T ceil_div(const T numerator, const T denominator)
78{
79 PH_ASSERT_GE(numerator, 0);
80 PH_ASSERT_GT(denominator, 0);
81
82 // Check for possible overflow when doing `numerator` + (`denominator` - 1).
83 // (i.e., MAX >= `numerator` + (`denominator` - 1), rearranged to minimize overflow)
84 PH_ASSERT_GE(std::numeric_limits<T>::max() - numerator, denominator - 1);
85
86 // We group the (`denominator` - 1) together as `numerator` is usually far larger than
87 // `denominator`, doing (`denominator` - 1) first has better chance to avoid an overflow
88 return (numerator + (denominator - 1)) / denominator;
89}
90
95template<std::integral T>
96inline T next_multiple(const T value, const T multiple)
97{
98 PH_ASSERT_GT(multiple, 0);
99
100 return ceil_div(value, multiple) * multiple;
101}
102
105template<std::integral T>
106inline T next_power_of_2_multiple(const T value, const T multiple)
107{
108 PH_ASSERT_GE(value, 0);
109 PH_ASSERT(is_power_of_2(multiple));
110
111 // Reference: https://stackoverflow.com/a/9194117
112
113 // Check for possible overflow when doing `value` + (`multiple` - 1).
114 // (see the implementation of `ceil_div()` for details about this test)
115 PH_ASSERT_GE(std::numeric_limits<T>::max() - value, multiple - 1);
116
117 // `& ~(multiple - 1)` is the same as `& -multiple` for two's complement arithmetic
118 return (value + (multiple - 1)) & (0 - multiple);
119
120 // Note:
121 // MSVC may emit C4146 warning on applying a unary negate operation on unsigned types. Subtracting a
122 // value from zero is the same as taking its negative, but using the binary subtraction operator avoids
123 // the warning about taking the negative of an unsigned value. Hence the `0 - multiple` instead of `-multiple`.
124 // Reference: https://stackoverflow.com/a/26893482
125}
126
127}// end namespace ph::math
#define PH_ASSERT_GE(a, b)
Definition assertion.h:67
#define PH_ASSERT_GT(a, b)
Definition assertion.h:61
#define PH_ASSERT(condition)
Definition assertion.h:49
Definition math_basics.h:16
T next_multiple(const T value, const T multiple)
Get the next number that is an integer multiple of multiple. Specifically, get the minimum number x =...
Definition math_basics.h:96
constexpr bool is_power_of(const T value)
Determines whether value is a power-of-BASE number. Checks the equality BASE^n == value,...
Definition math_basics.h:38
constexpr bool is_power_of_2(const T value)
Determines whether value is a power-of-2 number.
Definition math_basics.h:21
T next_power_of_2_multiple(const T value, const T multiple)
Same as next_multiple(T, T) except that multiple must be a power of 2 number.
Definition math_basics.h:106
T ceil_div(const T numerator, const T denominator)
Divide numerator by denominator and round up to integer. Both inputs must be positive integer....
Definition math_basics.h:77