qxLib
common.inl
Go to the documentation of this file.
1 /**
2 
3  @file common.inl
4  @author Khrapov
5  @date 29.04.2023
6  @copyright © Nick Khrapov, 2023. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<class T>
14 constexpr T abs(T value)
15 {
16  return value < 0 ? -value : value;
17 }
18 
19 template<class T>
20 constexpr bool epsilon_equal(T left, T right, T eps)
21 {
22  return abs(left - right) < eps;
23 }
24 
25 template<class T>
26 constexpr bool epsilon_zero(T value, T eps)
27 {
28  return abs(value) < eps;
29 }
30 
31 template<class T>
32 constexpr bool epsilon_less_equal(T left, T right, T eps)
33 {
34  return left < right || epsilon_equal(left, right, eps);
35 }
36 
37 template<class T>
38 constexpr bool epsilon_greater_equal(T left, T right, T eps)
39 {
40  return left > right || epsilon_equal(left, right, eps);
41 }
42 
43 template<std::integral T>
44 constexpr bool is_odd(T val)
45 {
46  return (val & 1) == 1;
47 }
48 
49 template<std::integral T>
50 constexpr bool is_even(T val)
51 {
52  return (val & 1) == 0;
53 }
54 
55 constexpr int gcd(int nFirst, int nSecond)
56 {
57  if (nFirst == 0 || nSecond == 0)
58  return 0;
59 
60  while (nSecond != 0)
61  {
62  const int nRemainder = nFirst % nSecond;
63  nFirst = nSecond;
64  nSecond = nRemainder;
65  }
66 
67  return abs(nFirst);
68 }
69 
70 constexpr int lcm(int nFirst, int nSecond)
71 {
72  if (nFirst == 0 || nSecond == 0)
73  return 0;
74 
75  nFirst = abs(nFirst);
76  nSecond = abs(nSecond);
77 
78  return nFirst / gcd(nFirst, nSecond) * nSecond;
79 }
80 
81 template<class T>
82 constexpr double pow(T number, int nPower)
83 {
84  static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>, "Integral or floating point required");
85 
86  if (!std::is_constant_evaluated())
87  {
88  const bool bNegativePower = nPower < 0;
89  const size_t nPositivePower = static_cast<size_t>(std::abs(nPower));
90 
91  double fResult = 1.0;
92  switch (nPositivePower)
93  {
94  case 0:
95  break;
96 
97  case 1:
98  fResult = static_cast<double>(number);
99  break;
100 
101  case 2:
102  fResult = static_cast<double>(number * number);
103  break;
104 
105  default:
106  const std::bitset<std::numeric_limits<int>::digits> powerBitSet(nPositivePower);
107 
108  std::array<double, std::numeric_limits<int>::digits> powers;
109 
110  powers[0] = static_cast<double>(number);
111 
112  size_t nCurPower = 1;
113  size_t nCurIndex = 1;
114 
115  while (nCurPower < nPositivePower)
116  {
117  powers[nCurIndex] = powers[nCurIndex - 1] * powers[nCurIndex - 1];
118  nCurPower *= 2;
119  nCurIndex++;
120  }
121 
122  for (size_t i = 0; i < nCurIndex; ++i)
123  if (powerBitSet.test(i))
124  fResult *= powers[i];
125 
126  break;
127  }
128 
129  return bNegativePower ? 1.0 / fResult : fResult;
130  }
131  else
132  {
133  double fResult = 1.0;
134  for (int i = 0; i < nPower; ++i)
135  fResult *= number;
136 
137  return fResult;
138  }
139 }
140 
141 template<std::integral I>
142 I maxpot(I nValue)
143 {
144  static_assert(std::is_integral_v<I>, "Integral required");
145 
146  if (nValue == 0)
147  return 0;
148 
149  std::bitset<std::numeric_limits<I>::digits> powers(static_cast<size_t>(abs(nValue)));
150 
151  I nPow = static_cast<I>(std::numeric_limits<I>::digits - 1);
152  while (!powers.test(static_cast<size_t>(nPow)))
153  --nPow;
154 
155  return nPow;
156 }
157 
158 // trick to determine if an integer is between two integers (inclusive)
159 // with only one comparison/branch
160 // https://stackoverflow.com/a/17095534/8021662
161 QX_DISABLE_MSVC_WARNINGS(4018 4388);
162 
163 template<class T, class compare_t>
164 constexpr bool between(T left, T value, T right, compare_t compare)
165 {
166  if constexpr (std::is_enum_v<T>)
167  {
168  i64 l = static_cast<i64>(left);
169  i64 r = static_cast<i64>(right);
170  i64 v = static_cast<i64>(value);
171  return between(l, v, r, compare);
172  }
173  else if constexpr (std::is_integral_v<T> && std::is_same_v<compare_t, std::less_equal<>>)
174  {
175  return compare(static_cast<size_t>(value - left), right - left);
176  }
177  else if constexpr (std::is_floating_point_v<T> && std::is_same_v<compare_t, std::less_equal<>>)
178  {
179  return epsilon_less_equal(left, value) && epsilon_less_equal(value, right);
180  }
181  else
182  {
183  return compare(left, value) && compare(value, right);
184  }
185 }
186 
187 template<class T, class compare_t>
188 constexpr bool between(T left, T value, T right)
189 {
190  QX_PUSH_SUPPRESS_MSVC_WARNINGS(4388);
191  return between(left, value, right, compare_t());
192  QX_POP_SUPPRESS_WARNINGS();
193 }
194 
195 QX_RESTORE_MSVC_WARNINGS(4018 4388);
196 
197 } // namespace qx
constexpr int lcm(int nFirst, int nSecond)
Least common multiple.
Definition: common.inl:70
constexpr bool between(T left, T value, T right, compare_t compare)
Checks if value is between left and right.
Definition: common.inl:164
constexpr bool epsilon_greater_equal(T left, T right, T eps=std::numeric_limits< T >::epsilon())
Constexpr comparison function for a user defined epsilon values.
Definition: common.inl:38
I maxpot(I nValue)
Max power of two in integer.
Definition: common.inl:142
constexpr bool is_odd(T val)
Check if value is odd.
Definition: common.inl:44
constexpr bool epsilon_zero(T value, T eps=std::numeric_limits< T >::epsilon())
Constexpr comparison with zero for a user defined epsilon values.
Definition: common.inl:26
constexpr T abs(T value)
Constexpr absolute value.
Definition: common.inl:14
constexpr bool epsilon_less_equal(T left, T right, T eps=std::numeric_limits< T >::epsilon())
Constexpr comparison function for a user defined epsilon values.
Definition: common.inl:32
constexpr bool is_even(T val)
Check if value is even.
Definition: common.inl:50
constexpr bool epsilon_equal(T left, T right, T eps=std::numeric_limits< T >::epsilon())
Constexpr comparison function for a user defined epsilon values.
Definition: common.inl:20
constexpr double pow(T number, int nPower)
Power function for integer power.
Definition: common.inl:82
constexpr int gcd(int nFirst, int nSecond)
Greatest common divisor.
Definition: common.inl:55