jaulib v1.4.1
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
test_int_math01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2024 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24#include <thread>
25#include <cassert>
26#include <cinttypes>
27#include <cstring>
28
29#include <jau/cpp_lang_util.hpp>
30#include <jau/test/catch2_ext.hpp>
31
32#include <jau/int_math.hpp>
33
34using namespace jau;
35using namespace jau::int_literals;
36
37TEST_CASE( "Int Math Test 00", "[sign][arithmetic][math]" ) {
38 REQUIRE( 1 == jau::sign( 1) );
39 REQUIRE( 0 == jau::sign( 0) );
40 REQUIRE( -1 == jau::sign(-1) );
41 REQUIRE( 1 == jau::sign( 1_i64) );
42 REQUIRE( 0 == jau::sign( 0_i64) );
43 REQUIRE( -1 == jau::sign(-1_i64) );
44 REQUIRE( 1 == jau::sign( 1_u64) );
45 REQUIRE( 0 == jau::sign( 0_u64) );
46
47 REQUIRE( 1 == jau::sign( std::numeric_limits<uint64_t>::max() ) );
48 REQUIRE( 1 == jau::sign( std::numeric_limits<int64_t>::max() ) );
49 REQUIRE( -1 == jau::sign( std::numeric_limits<int64_t>::min() ) );
50}
51TEST_CASE( "Int Math Test 01", "[round][align][arithmetic][math]" ) {
52 {
53 REQUIRE( 0_u32 == jau::round_up( 0_u32, 1_u32) );
54 REQUIRE( 1_u32 == jau::round_up( 1_u32, 1_u32) );
55 REQUIRE( 2_u32 == jau::round_up( 2_u32, 1_u32) );
56
57 REQUIRE( 0_u32 == jau::round_up( 0_u32, 8_u32) );
58 REQUIRE( 8_u32 == jau::round_up( 1_u32, 8_u32) );
59 REQUIRE( 8_u32 == jau::round_up( 7_u32, 8_u32) );
60 REQUIRE( 8_u32 == jau::round_up( 8_u32, 8_u32) );
61 REQUIRE( 16_u32 == jau::round_up( 9_u32, 8_u32) );
62 }
63 {
64 REQUIRE( 0_u32 == jau::round_down( 0_u32, 1_u32) );
65 REQUIRE( 1_u32 == jau::round_down( 1_u32, 1_u32) );
66 REQUIRE( 2_u32 == jau::round_down( 2_u32, 1_u32) );
67
68 REQUIRE( 0_u32 == jau::round_down( 0_u32, 8_u32) );
69 REQUIRE( 0_u32 == jau::round_down( 1_u32, 8_u32) );
70 REQUIRE( 0_u32 == jau::round_down( 7_u32, 8_u32) );
71 REQUIRE( 8_u32 == jau::round_down( 8_u32, 8_u32) );
72 REQUIRE( 8_u32 == jau::round_down( 9_u32, 8_u32) );
73 }
74}
75TEST_CASE( "Int Math Test 02", "[abs][arithmetic][math]" ) {
76 {
77 // abs unsigned integral
78 REQUIRE( 1_u64 == jau::abs( 1_u64) );
79 REQUIRE( std::numeric_limits<uint64_t>::max() == jau::abs( std::numeric_limits<uint64_t>::max() ) );
80
81 // abs float
82 REQUIRE( 1.0f == jau::abs( 1.0f ) );
83 REQUIRE( 1.0f == jau::abs(-1.0f ) );
84 REQUIRE( std::numeric_limits<float>::max() == jau::abs( std::numeric_limits<float>::max() ) );
85 REQUIRE( std::numeric_limits<float>::min() == jau::abs( std::numeric_limits<float>::min() ) );
86 REQUIRE( std::numeric_limits<float>::max() == jau::abs( -std::numeric_limits<float>::max() ) );
87 }
88 {
89 // abs signed integral
90 REQUIRE( 1 == jau::abs( 1) );
91 REQUIRE( 1 == jau::abs(-1) );
92 REQUIRE( 1 == jau::ct_abs( 1) );
93 REQUIRE( 1 == jau::ct_abs(-1) );
94 REQUIRE( 1_i64 == jau::abs( 1_i64) );
95 REQUIRE( 1_i64 == jau::abs(-1_i64) );
96 REQUIRE( 1_i64 == jau::ct_abs( 1_i64) );
97 REQUIRE( 1_i64 == jau::ct_abs(-1_i64) );
98
99 REQUIRE( std::numeric_limits<int64_t>::max() == jau::abs( std::numeric_limits<int64_t>::max() ) );
100 REQUIRE( std::numeric_limits<int64_t>::max() == jau::abs( std::numeric_limits<int64_t>::min() ) );
101
102 REQUIRE( std::numeric_limits<int64_t>::max() == jau::ct_abs( std::numeric_limits<int64_t>::max() ) );
103 // REQUIRE( std::numeric_limits<int64_t>::min() == jau::ct_abs( std::numeric_limits<int64_t>::min() ) ); // UB
104
105 REQUIRE( std::numeric_limits<int64_t>::max() == std::abs( std::numeric_limits<int64_t>::max() ) );
106 // REQUIRE( std::numeric_limits<int64_t>::max() == std::abs( std::numeric_limits<int64_t>::min() ) ); // UB
107
108 REQUIRE( INT32_MAX == jau::abs( INT32_MAX ) );
109 REQUIRE( INT32_MAX == jau::abs( INT32_MAX ) );
110
111 REQUIRE( INT32_MAX == jau::ct_abs( INT32_MAX ) );
112 // REQUIRE( INT32_MIN == jau::ct_abs( INT32_MIN ) ); // UB
113
114 REQUIRE( INT32_MAX == std::abs( INT32_MAX ) );
115 // REQUIRE( INT32_MAX == std::abs( INT32_MIN ) ); // UB
116 }
117}
118
119TEST_CASE( "Int Math Test 03a", "[min][max][clip][arithmetic][math]" ) {
120 REQUIRE( 0 == jau::min( 0, INT32_MAX ) );
121 REQUIRE( INT32_MAX == jau::max( 0, INT32_MAX ) );
122 REQUIRE( INT32_MAX-1== jau::min( INT32_MAX-1, INT32_MAX ) );
123 REQUIRE( INT32_MAX == jau::max( INT32_MAX-1, INT32_MAX ) );
124 REQUIRE( INT32_MIN == jau::min( 0, INT32_MIN ) );
125 REQUIRE( 0 == jau::max( 0, INT32_MIN ) );
126 REQUIRE( INT32_MIN == jau::min( INT32_MIN+1, INT32_MIN ) );
127 REQUIRE( INT32_MIN+1== jau::max( INT32_MIN+1, INT32_MIN ) );
128 REQUIRE( 0 == jau::clamp( 0, -10, 10 ) );
129 REQUIRE( -10 == jau::clamp( INT32_MIN, -10, 10 ) );
130 REQUIRE( 10 == jau::clamp( INT32_MAX, -10, 10 ) );
131}
132
133TEST_CASE( "Int Math Test 03b", "[ct_min][ct_max][clip2][arithmetic][math]" ) {
134 REQUIRE( 0 == jau::ct_min( 0, INT32_MAX ) );
135 REQUIRE( INT32_MAX == jau::ct_max( 0, INT32_MAX ) );
136 REQUIRE( INT32_MAX-1== jau::ct_min( INT32_MAX-1, INT32_MAX ) );
137 REQUIRE( INT32_MAX == jau::ct_max( INT32_MAX-1, INT32_MAX ) );
138 REQUIRE( INT32_MIN+1 == jau::ct_min( 0, INT32_MIN+1 ) ); // limitation: `MIN <= x - y <= MAX`
139 REQUIRE( 0 == jau::ct_max( 0, INT32_MIN+1 ) ); // limitation: `MIN <= x - y <= MAX`
140 REQUIRE( INT32_MIN == jau::ct_min( INT32_MIN+1, INT32_MIN ) );
141 REQUIRE( INT32_MIN+1== jau::ct_max( INT32_MIN+1, INT32_MIN ) );
142 REQUIRE( 0 == jau::ct_clamp( 0, -10, 10 ) );
143 REQUIRE( -10 == jau::ct_clamp( INT32_MIN+11, -10, 10 ) ); // limitation: `MIN <= x - y <= MAX`
144 REQUIRE( 10 == jau::ct_clamp( INT32_MAX-11, -10, 10 ) ); // limitation: `MIN <= x - y <= MAX`
145}
146
147
148TEST_CASE( "Int Math Test 10", "[bits][arithmetic][math]" ) {
149 {
150 REQUIRE( 0b0000000000000000U == ct_masked_merge( 0b0000000000000000U, 0b0000000000000000U, 0b0000000000000000U ) );
151 REQUIRE( 0b1100000000000011U == ct_masked_merge( 0b1111111100000000U, 0b1100000000000000U, 0b0000000000000011U ) );
152 REQUIRE( 64_u32 == ct_masked_merge( 0b1111111111111111U, 64_u32, 256_u32 ) );
153 REQUIRE( 256_u32 == ct_masked_merge( 0b0000000000000000U, 64_u32, 256_u32 ) );
154 }
155 {
156 REQUIRE( true == is_power_of_2( 2_u32 ) );
157 REQUIRE( true == is_power_of_2( 4_u32 ) );
158 REQUIRE( true == is_power_of_2( 64_u32 ) );
159 }
160 {
161 if( is_cxx20() ) {
162 REQUIRE( 1u == std::bit_ceil(0u) );
163 REQUIRE( 1u == std::bit_ceil(1u) );
164 REQUIRE( 2u == std::bit_ceil(2u) );
165 REQUIRE( 4u == std::bit_ceil(3u) );
166 REQUIRE(64u == std::bit_ceil(63u) );
167 }
168 REQUIRE( 1 == bit_ceil(0_u32) );
169 REQUIRE( 1 == bit_ceil(1_u32) );
170 REQUIRE( 2 == bit_ceil(2_u32) );
171 REQUIRE( 4 == bit_ceil(3_u32) );
172 REQUIRE(64 == bit_ceil(63_u32) );
173 }
174 {
175 REQUIRE( 0 == ct_bit_count( 0b00000000000000000000000000000000UL ) );
176 REQUIRE( 1 == ct_bit_count( 0b00000000000000000000000000000001UL ) );
177 REQUIRE( 1 == ct_bit_count( 0b10000000000000000000000000000000UL ) );
178 REQUIRE( 16 == ct_bit_count( 0b10101010101010101010101010101010UL ) );
179 REQUIRE( 16 == ct_bit_count( 0b01010101010101010101010101010101UL ) );
180 REQUIRE( 32 == ct_bit_count( 0b11111111111111111111111111111111UL ) );
181
182 REQUIRE( 0 == bit_count( 0b00000000000000000000000000000000UL ) );
183 REQUIRE( 1 == bit_count( 0b00000000000000000000000000000001UL ) );
184 REQUIRE( 1 == bit_count( 0b10000000000000000000000000000000UL ) );
185 REQUIRE( 16 == bit_count( 0b10101010101010101010101010101010UL ) );
186 REQUIRE( 16 == bit_count( 0b01010101010101010101010101010101UL ) );
187 REQUIRE( 32 == bit_count( 0b11111111111111111111111111111111UL ) );
188 }
189 {
190 REQUIRE( 0 == high_bit( 0b00000000U ) );
191 REQUIRE( 1 == high_bit( 0b00000001U ) );
192 REQUIRE( 2 == high_bit( 0b00000010U ) );
193 REQUIRE( 2 == high_bit( 0b00000011U ) );
194 REQUIRE( 8 == high_bit( 0b11000011U ) );
195
196 REQUIRE( 64 == high_bit( 0b1100001111000011110000111100001111000011110000111100001111000011UL ) );
197 }
198}
199TEST_CASE( "Int Math Test 20", "[add][sub][overflow][arithmetic][math]" ) {
200 {
201 {
202 {
203 uint64_t a = 1, b = 2, r;
204 REQUIRE( false == jau::add_overflow(a, b, r) );
205 REQUIRE( a + b == r );
206 }
207 {
208 uint64_t a = std::numeric_limits<uint64_t>::max()-2, b = 2, r;
209 REQUIRE( false == jau::add_overflow(a, b, r) );
210 REQUIRE( a + b == r );
211 }
212 {
213 uint64_t a = std::numeric_limits<uint64_t>::max(), b = 2, r;
214 REQUIRE( true == jau::add_overflow(a, b, r) );
215 }
216 }
217 {
218 {
219 uint64_t a = 2, b = 1, r;
220 REQUIRE( false == jau::sub_overflow(a, b, r) );
221 REQUIRE( a - b == r );
222 }
223 {
224 uint64_t a = std::numeric_limits<uint64_t>::min()+2, b = 2, r;
225 REQUIRE( false == jau::sub_overflow(a, b, r) );
226 REQUIRE( a - b == r );
227 }
228 {
229 uint64_t a = 1, b = 2, r;
230 REQUIRE( true == jau::sub_overflow(a, b, r) );
231 }
232 {
233 uint64_t a = std::numeric_limits<uint64_t>::min(), b = 2, r;
234 REQUIRE( true == jau::sub_overflow(a, b, r) );
235 }
236 }
237 }
238 {
239 {
240 {
241 int64_t a = 1, b = 2, r;
242 REQUIRE( false == jau::add_overflow(a, b, r) );
243 REQUIRE( a + b == r );
244 }
245 {
246 int64_t a = std::numeric_limits<int64_t>::max()-2, b = 2, r;
247 REQUIRE( false == jau::add_overflow(a, b, r) );
248 REQUIRE( a + b == r );
249 }
250 {
251 int64_t a = std::numeric_limits<int64_t>::max(), b = 2, r;
252 REQUIRE( true == jau::add_overflow(a, b, r) );
253 }
254 }
255 {
256 {
257 int64_t a = 2, b = 1, r;
258 REQUIRE( false == jau::sub_overflow(a, b, r) );
259 REQUIRE( a - b == r );
260 }
261 {
262 int64_t a = std::numeric_limits<int64_t>::min()+2, b = 2, r;
263 REQUIRE( false == jau::sub_overflow(a, b, r) );
264 REQUIRE( a - b == r );
265 }
266 {
267 int64_t a = 1, b = 2, r;
268 REQUIRE( false == jau::sub_overflow(a, b, r) );
269 REQUIRE( a - b == r );
270 }
271 {
272 uint64_t a = std::numeric_limits<uint64_t>::min(), b = 2, r;
273 REQUIRE( true == jau::sub_overflow(a, b, r) );
274 }
275 }
276 }
277}
278TEST_CASE( "Int Math Test 21", "[mul][overflow][arithmetic][math]" ) {
279 {
280 {
281 uint64_t a = 1, b = 2, r;
282 REQUIRE( false == jau::mul_overflow(a, b, r) );
283 REQUIRE( a * b == r );
284 }
285 {
286 uint64_t a = std::numeric_limits<uint64_t>::max()/2, b = 2, r;
287 REQUIRE( false == jau::mul_overflow(a, b, r) );
288 REQUIRE( a * b == r );
289 }
290 {
291 uint64_t a = std::numeric_limits<uint64_t>::max(), b = 2, r;
292 REQUIRE( true == jau::mul_overflow(a, b, r) );
293 }
294 }
295 {
296 {
297 int64_t a = 1, b = 2, r;
298 REQUIRE( false == jau::mul_overflow(a, b, r) );
299 REQUIRE( a * b == r );
300 }
301 {
302 int64_t a = std::numeric_limits<int64_t>::max()/2, b = 2, r;
303 REQUIRE( false == jau::mul_overflow(a, b, r) );
304 REQUIRE( a * b == r );
305 }
306 {
307 int64_t a = std::numeric_limits<int64_t>::max(), b = 2, r;
308 REQUIRE( true == jau::mul_overflow(a, b, r) );
309 }
310 }
311}
312
313constexpr static size_t log2_byteshift2(const size_t bytesize) noexcept {
314 size_t bitsize = bytesize * 8, r = 0;
315 while ( bitsize >>= 1 ) {
316 ++r;
317 }
318 return r;
319}
320
321TEST_CASE("Int Math Test 22", "[log2_byteshift][arithmetic][math]") {
322 for(size_t bytesz = 1; bytesz < 4096; bytesz<<=1) {
323 size_t bitsz = bytesz*8;
324 size_t l2 = (size_t)std::log2(bitsz);
325 size_t shift1 = jau::log2_byteshift(bytesz);
326 size_t shift2 = log2_byteshift2(bytesz);
327 fprintf(stderr, "bytesz %zu, bitsz %zu: log2 %zu, shift[1 %zu, 2 %zu]\n",
328 bytesz, bitsz, l2, shift1, shift2);
329 REQUIRE( l2 == shift1 );
330 REQUIRE( l2 == shift2 );
331 }
332 // non-power2 tests
333 REQUIRE(0 == jau::log2_byteshift(0));
334 REQUIRE(0 == jau::log2_byteshift(3));
335 REQUIRE(0 == jau::log2_byteshift(65));
336 REQUIRE(0 == jau::log2_byteshift(257));
337 REQUIRE(0 == jau::log2_byteshift(256+8));
338}
339
constexpr uint32_t ct_bit_count(uint32_t n) noexcept
Returns the number of set bits within given 32bit integer (w/o branching) in O(1) and constant time (...
constexpr T ct_masked_merge(T mask, T a_if_masked, T b_if_unmasked) noexcept
Returns merged a_if_masked bits selected by mask 1 bits and b_if_unmasked bits selected by mask 0 bit...
constexpr T ct_max(const T x, const T y) noexcept
Returns the maximum of two integrals for MIN <= x - y <= MAX (w/o branching) in O(1) and constant tim...
constexpr T ct_min(const T x, const T y) noexcept
Returns the minimum of two integrals for MIN <= x - y <= MAX (w/o branching) in O(1) and constant tim...
constexpr T ct_clamp(const T x, const T min_val, const T max_val) noexcept
Returns constrained integral value to lie between given min- and maximum value for MIN <= x - y <= MA...
constexpr T ct_abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/o branching) in O(1) and constant time (CT),...
consteval_cxx20 bool is_cxx20() noexcept
Returns true if compiled with >= C++20.
constexpr size_t log2_byteshift(const size_t bytesize) noexcept
Returns log2(bytesize*8), e.g.
Definition int_math.hpp:150
constexpr bool mul_overflow(const T a, const T b, T &res) noexcept
Integer overflow aware multiplication returning true if overflow occurred, otherwise false having the...
Definition int_math.hpp:335
constexpr T clamp(const T x, const T min_val, const T max_val) noexcept
Returns constrained integral value to lie between given min- and maximum value (w/ branching) in O(1)...
constexpr T round_up(const T n, const U align_to)
Round up w/ branching in O(1)
Definition int_math.hpp:96
constexpr nsize_t high_bit(T x)
Return the index of the highest set bit w/ branching (loop) in O(n/2).
Definition int_math.hpp:203
constexpr bool sub_overflow(const T a, const T b, T &res) noexcept
Integer overflow aware subtraction returning true if overflow occurred, otherwise false having the re...
Definition int_math.hpp:304
constexpr bool add_overflow(const T a, const T b, T &res) noexcept
Integer overflow aware addition returning true if overflow occurred, otherwise false having the resul...
Definition int_math.hpp:273
constexpr T round_down(T n, U align_to)
Round down w/ branching in O(1)
Definition int_math.hpp:116
constexpr T bit_ceil(const T n) noexcept
If the given n is not is_power_of_2() return next_power_of_2(), otherwise return n unchanged.
Definition int_math.hpp:186
constexpr int sign(const T x) noexcept
Returns the value of the sign function (w/o branching ?) in O(1).
Definition base_math.hpp:81
constexpr bool is_power_of_2(const T x) noexcept
Power of 2 test in O(1), i.e.
Definition int_math.hpp:134
constexpr T min(const T x, const T y) noexcept
Returns the minimum of two integrals (w/ branching) in O(1)
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
constexpr size_t bit_count(T n) noexcept
Returns the number of set bits within given unsigned integral.
Definition int_math.hpp:220
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
static constexpr size_t log2_byteshift2(const size_t bytesize) noexcept
TEST_CASE("Int Math Test 00", "[sign][arithmetic][math]")