jaulib v1.4.0-2-g788cf73
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
test_fractions_01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2022 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 <cassert>
25#include <cinttypes>
26#include <cstring>
27#include <thread>
28
29#include <jau/basic_types.hpp>
30#include <jau/cpp_lang_util.hpp>
31#include <jau/debug.hpp>
32#include <jau/test/catch2_ext.hpp>
33
34using namespace jau;
35using namespace jau::fractions_i64_literals;
36using namespace jau::int_literals;
37
38#if 0
39static fraction<int64_t> ratio_multiply(const fraction<int64_t>& r1, const fraction<int64_t>& r2) {
40 const uint64_t gcd1 = gcd<uint64_t>((uint64_t)abs(r1.num), r2.denom);
41 const uint64_t gcd2 = gcd<uint64_t>((uint64_t)abs(r2.num), r1.denom);
42
43 return fraction<int64_t>( ( r1.num / gcd1 ) * ( r2.num / gcd2),
44 ( r1.denom / gcd2 ) * ( r2.denom / gcd1) );
45}
46
47static fraction<int64_t> ratio_divide(const fraction<int64_t>& r1, const fraction<int64_t>& r2) {
48 return ratio_multiply(r1, fraction<int64_t>(r2.denom, r2.num));
49}
50
51static fraction<int64_t> duration_common_type(const fraction<int64_t>& p1, const fraction<int64_t>& p2) {
52 const uint64_t gcd_num = gcd<uint64_t>((uint64_t)abs(p1.num), (uint64_t)abs(p2.num));
53 const uint64_t gcd_den = gcd<uint64_t>(p1.denom, p2.denom);
54 return fraction<int64_t>( gcd_num * jau::sign(p1.num) * jau::sign(p2.num), ( p1.denom / gcd_den ) * p2.denom );
55}
56#endif
57
58template<typename int_type>
59static void test_gcd_fract(const int_type n, const std::make_unsigned_t<int_type> d,
60 const int_type exp_gcd, const int_type exp_num, const std::make_unsigned_t<int_type> exp_denom) {
61 {
62 const int_type n1 = sign(n) * abs(n);
63 const std::make_unsigned_t<int_type> d1 = sign(d) * abs(d);
64 REQUIRE( n == n1 );
65 REQUIRE( d == d1 );
66 }
67
68 const int_type _gcd = gcd( n, static_cast<int_type>(d) );
69 REQUIRE( exp_gcd == _gcd );
70
71 fraction<int_type> f1(n, d);
72 REQUIRE( exp_num == f1.num );
73 REQUIRE( exp_denom == f1.denom);
74}
75
76template<typename int_type>
77static void test_gcd_fract_pm(const int_type n, const std::make_unsigned_t<int_type> d,
78 const int_type exp_gcd, const int_type exp_num, const std::make_unsigned_t<int_type> exp_denom) {
79 test_gcd_fract( n, d, exp_gcd, exp_num, exp_denom);
80 test_gcd_fract(-n, d, exp_gcd, -exp_num, exp_denom);
81}
82
83template<typename int_type>
85 const fraction<int_type>& exp_max, const fraction<int_type>& exp_min,
86 const fraction<int_type>& exp_sum, const fraction<int_type>& exp_diff,
87 const fraction<int_type>& exp_mul, const fraction<int_type>& exp_div)
88{
89 const bool show_double = true;
90 INFO_STR( "max(a "+a.toString(show_double)+", b "+b.toString(show_double)+") = "+max(a,b).toString(show_double));
91 INFO_STR( "min(a "+a.toString(show_double)+", b "+b.toString(show_double)+") = "+min(a,b).toString(show_double));
92 INFO_STR( "a "+a.toString(show_double)+" + b "+b.toString(show_double)+" = "+(a+b).toString(show_double));
93 INFO_STR( "a "+a.toString(show_double)+" - b "+b.toString(show_double)+" = "+(a-b).toString(show_double));
94 INFO_STR( "a "+a.toString(show_double)+" * b "+b.toString(show_double)+" = "+(a*b).toString(show_double));
95 INFO_STR( "a "+a.toString(show_double)+" / b "+b.toString(show_double)+" = "+(a/b).toString(show_double));
96 {
97 const double epsilon = std::numeric_limits<double>::epsilon();
98 const double ad = a.to_double();
99 const double bd = b.to_double();
100 if( std::abs( ad - bd ) <= epsilon ) {
101 REQUIRE( a == b );
102 REQUIRE( !(a != b) );
103 REQUIRE( a <= b );
104 REQUIRE( a >= b );
105 } else if( std::abs( ad - bd ) > epsilon ) {
106 REQUIRE( a != b );
107 REQUIRE( !(a == b) );
108 if( ad - bd < -epsilon ) {
109 REQUIRE( a < b );
110 REQUIRE( a <= b );
111 REQUIRE( b > a );
112 REQUIRE( b >= a );
113 } else {
114 REQUIRE( a > b );
115 REQUIRE( a >= b );
116 REQUIRE( b < a );
117 REQUIRE( b <= a );
118 }
119 }
120 }
121 {
122 fraction<int_type> has_max = max(a, b);
123 fraction<int_type> has_min = min(a, b);
124 REQUIRE_MSG( "exp "+to_string(exp_max)+" == has "+to_string(has_max), exp_max == has_max );
125 REQUIRE_MSG( "exp "+to_string(exp_min)+" == has "+to_string(has_min), exp_min == has_min );
126 REQUIRE( has_max >= has_min );
127 REQUIRE( has_min <= has_max );
128 }
129 {
130 const fraction<int_type> has_sum = a + b;
131 const double exp_double = a.to_double() + b.to_double();
132 const double has_double = has_sum.to_double();
133 REQUIRE_MSG( "exp "+std::to_string(exp_double)+" == has "+std::to_string(has_double), abs( exp_double - has_double ) <= std::numeric_limits<double>::epsilon() );
134 REQUIRE_MSG( "exp "+to_string(exp_sum)+" == has "+to_string(has_sum), exp_sum == has_sum );
135 }
136 {
137 fraction<int_type> has_diff = a - b;
138 const double exp_double = a.to_double() - b.to_double();
139 const double has_double = has_diff.to_double();
140 REQUIRE_MSG( "exp "+std::to_string(exp_double)+" == has "+std::to_string(has_double), abs( exp_double - has_double ) <= std::numeric_limits<double>::epsilon() );
141 REQUIRE_MSG( "exp "+to_string(exp_diff)+" == has "+to_string(has_diff), exp_diff == has_diff );
142 }
143 {
144 fraction<int_type> has_mul = a * b;
145 const double exp_double = a.to_double() * b.to_double();
146 const double has_double = has_mul.to_double();
147 REQUIRE_MSG( "exp "+std::to_string(exp_double)+" == has "+std::to_string(has_double), abs( exp_double - has_double ) <= std::numeric_limits<double>::epsilon() );
148 REQUIRE_MSG( "exp "+to_string(exp_mul)+" == has "+to_string(has_mul), exp_mul == has_mul);
149 }
150 {
151 fraction<int_type> has_div = a / b;
152 const double exp_double = a.to_double() / b.to_double();
153 const double has_double = has_div.to_double();
154 REQUIRE_MSG( "exp "+std::to_string(exp_double)+" == has "+std::to_string(has_double), abs( exp_double - has_double ) <= std::numeric_limits<double>::epsilon() );
155 REQUIRE_MSG( "exp "+to_string(exp_div)+" == has "+to_string(has_div), exp_div == has_div);
156 }
157 {
158 const fraction<int_type> step(1, a.denom);
159 const fraction<int_type> lim(a + ( step * (int_type)10 ));
161 int count;
162 for(count = 0; i < lim; i+=step, ++count) { }
163 REQUIRE( i == lim );
164 REQUIRE( i > a );
165 REQUIRE( 10 == count );
166
167 i+=step;
168 REQUIRE( i > lim );
169 REQUIRE( i == lim + step );
170 }
171 if( !std::is_unsigned_v<int_type> ) {
172 const fraction<int_type> step(1, a.denom);
173 const fraction<int_type> lim(a - ( step * (int_type)10 ));
175 int count;
176 for(count = 0; i > lim; i-=step, ++count) { }
177 REQUIRE( i == lim );
178 REQUIRE( i < a );
179 REQUIRE( 10 == count );
180
181 i-=step;
182 REQUIRE( i < lim );
183 REQUIRE( i == lim - step );
184 }
185}
186
187template<typename Rep, typename Period, typename int_type>
188static void test_duration(const fraction<int_type>& a, const std::chrono::duration<Rep, Period>& dur_ref,
189 const Rep exp_count)
190{
191 INFO_STR( " given duration: ( " + std::to_string(dur_ref.count()) + " * " + std::to_string(Period::num) + " = " + std::to_string(dur_ref.count() * Period::num) + " ) / " + std::to_string(Period::den) );
192 {
193 const int64_t d_num = a.to_num_of( fraction_i64(Period::num, Period::den) );
194 std::chrono::duration<Rep, Period> d = a.to_duration( dur_ref );
195 INFO_STR( " fraction-1 " + a.toString(true) + " -> duration_count " + std::to_string( d_num ) + ", duration " + std::to_string( d.count() ) );
196 INFO_STR( " resulting duration-1: ( " + std::to_string(d.count()) + " * " + std::to_string(Period::num) + " = " + std::to_string(d.count() * Period::num) + " ) / " + std::to_string(Period::den) );
197
198 // fully functional conversion check
200 INFO_STR( " reconverted fraction-2 " + b.toString(true));
201 REQUIRE( exp_count == d_num );
202 REQUIRE( exp_count == d.count() );
203 REQUIRE( a == b );
204 }
205#if 0
206 {
207 typename std::chrono::duration<Rep, Period>::rep d_count = a.to_duration_count( dur_ref );
208 auto d = a.to_auto_duration();
209 INFO_STR( " fraction-2 " + a.toString(true) + " -> duration_count " + std::to_string( d_count ) + ", duration " + std::to_string( d.count() ) );
210 INFO_STR( " resulting duration-2: ( " + std::to_string(d.count()) + " * " + std::to_string(Period::num) + " = " + std::to_string(d.count() * Period::num) + " ) / " + std::to_string(Period::den) );
211 INFO_STR( " resulting duration-2: ( " + std::to_string(d.count()) + " * " + std::to_string(decltype(d)::num) + " = " + std::to_string(d.count() * decltype(d)::num) + " ) / " + std::to_string(decltype(d)::den) );
212
213 // fully functional conversion check
215 INFO_STR( " reconverted fraction-2 " + b.toString(true));
216 REQUIRE( exp_count == d_count );
217 REQUIRE( exp_count == d.count() );
218 REQUIRE( a == b );
219 }
220#endif
221}
222
223
224TEST_CASE( "Fraction Types Test 00", "[fraction][type]" ) {
225 {
226 INFO_STR(" is_trivially_copyable_v<fraction_i64>: " + std::to_string(std::is_trivially_copyable_v<fraction_i64>));
227 INFO_STR(" is_trivially_copyable<fraction_timespec>: " + std::to_string(std::is_trivially_copyable_v<fraction_timespec>));
228 REQUIRE( true == std::is_trivially_copyable_v<fraction_i64> );
229 REQUIRE( true == std::is_trivially_copyable_v<fraction_timespec> );
231 (void)check_type_01;
232 }
233 {
234 INFO_STR(" is_trivially_copyable_v<fraction_i64>: " + std::to_string(std::is_trivially_copyable_v<fraction_i64>));
235 REQUIRE( true == std::is_trivially_copyable_v<fraction_i64> );
237 (void)check_type_01;
238 }
239 {
240 REQUIRE( INT64_MAX == std::numeric_limits<int64_t>::max() );
241 REQUIRE( INT64_MIN == std::numeric_limits<int64_t>::min() );
242
243 REQUIRE( UINT64_MAX == std::numeric_limits<uint64_t>::max() );
244 }
245 {
246 // copy-ctor
247 fraction<int> a(1, 6);
248 fraction<int> b(a);
249 REQUIRE( a == b );
250 }
251 {
252 // move-ctor
253 fraction<int> a0(1, 6);
254 fraction<int> a1(a0);
255 fraction<int> b( a0 );
256 REQUIRE( a1 == b );
257 }
258 {
259 // assignment
260 fraction<int> a(1, 6);
261 fraction<int> b(6, 1);
262 b = a;
263 REQUIRE( a == b );
264 }
265 {
266 // move-assignment
267 fraction<int> a(1, 6);
268 fraction<int> a2(a);
269 fraction<int> b(6, 1);
270 b = a2;
271 REQUIRE( a == b );
272 }
273 {
274 REQUIRE( fractions_i64::zero == 0_s );
275 REQUIRE( fractions_i64::zero == 0_one );
276
277 REQUIRE( fractions_i64::one == 1_one );
278 REQUIRE( fractions_i64::one == 1_s );
279
280 REQUIRE( 3_i64*fractions_i64::tera == 3_T );
281 REQUIRE( 3_i64*fractions_i64::giga == 3_G );
282 REQUIRE( 3_i64*fractions_i64::mega == 3_M );
283 REQUIRE( 3_i64*fractions_i64::kilo == 3_k );
284 REQUIRE( 3_i64*fractions_i64::one == 3_one );
285 REQUIRE( 3_i64*fractions_i64::milli == 3_m );
286 REQUIRE( 3_i64*fractions_i64::micro == 3_u );
287 REQUIRE( 3_i64*fractions_i64::nano == 3_n );
288 REQUIRE( 3_i64*fractions_i64::pico == 3_p );
289
290 REQUIRE( 3_i64*fractions_i64::days == 3_d );
291 REQUIRE( 3_i64*fractions_i64::hours == 3_h );
292 REQUIRE( 3_i64*fractions_i64::minutes == 3_min );
293 REQUIRE( 3_i64*fractions_i64::seconds == 3_s );
294 REQUIRE( 3_i64*fractions_i64::milli == 3_ms );
295 REQUIRE( 3_i64*fractions_i64::micro == 3_us );
296 REQUIRE( 3_i64*fractions_i64::nano == 3_ns );
297 }
298}
299
300TEST_CASE( "Fraction GCD and Modulo Test 00", "[integer][fraction][gcd]" ) {
301 test_gcd_fract<int>(0, 0, 0, 0, 1);
302 test_gcd_fract<uint32_t>(0, 0, 0, 0, 1);
303
304 test_gcd_fract_pm<int>(15, 5, 5, 3, 1);
305 test_gcd_fract_pm<int>(17, 5, 1, 17, 5);
306
307 test_gcd_fract<uint32_t>(15, 5, 5, 3, 1);
308 test_gcd_fract<uint32_t>(17, 5, 1, 17, 5);
309}
310
311static void test_to_num_of(const int64_t exp, const fraction<int64_t>& v, const fraction<int64_t>& new_base, bool exp_overflow=false) noexcept {
312 bool overflow = false;
313 int64_t rr = v.to_num_of(new_base, &overflow);
314 INFO_STR(" value " + v.toString() );
315 INFO_STR(" new_base " + new_base.toString() );
316 std::string rr_s = exp == rr ? " - OK " : " - ********* ERROR ";
317 INFO_STR(" rr " + std::to_string(rr) + " =?= " + std::to_string(exp) + rr_s + ", overflow[exp " + std::to_string(exp_overflow) + ", has " + std::to_string(overflow) + "]");
318 if constexpr ( false ) {
319 // leaving elaboration code in .. for future testing overflows
320 const uint64_t _gcd = gcd<uint64_t>( v.denom, new_base.denom );
321 const uint64_t _lcm = ( v.denom * new_base.denom ) / _gcd;
322 int64_t r0 = ( v.num * (int64_t)( _lcm / v.denom ) ) / new_base.num;
323 int64_t r2 = ( v.num * (int64_t)new_base.denom ) / ( (int64_t) v.denom ) / new_base.num;
324 INFO_STR(" gcd " + std::to_string(_gcd) );
325 INFO_STR(" lcm " + std::to_string(_lcm) );
326 INFO_STR(" lcm / v_denom " + std::to_string( _lcm / v.denom) );
327 INFO_STR(" v_num * nb_denum " + std::to_string( v.num * (int64_t)new_base.denom ) );
328 std::string r0_s = exp == r0 ? " - OK " : " - ********* ERROR ";
329 INFO_STR(" r0 " + std::to_string(r0) + " =?= " + std::to_string(exp) + r0_s);
330 std::string r2_s = exp == r2 ? " - OK " : " - ********* ERROR ";
331 INFO_STR(" r2 " + std::to_string(r2) + " =?= " + std::to_string(exp) + r2_s);
332 }
333 REQUIRE( exp_overflow == overflow );
334 if( !exp_overflow ) {
335 REQUIRE( exp == rr );
336 }
337}
338
339TEST_CASE( "Fraction Cast Test 01.1", "[integer][fraction][type][to_num_of]" ) {
340 {
341 test_to_num_of( 2_i64, fractions_i64::one, fraction_i64(1_i64, 2_u64) ); // one -> halves
346 }
347 {
348 fraction_i64 a ( 10_s + 400_ms );
349 fraction_i64 b ( 0_s + 400_ms );
350 fraction_i64 exp_sum ( 10_s + 800_ms );
351
353 test_to_num_of( 10'400'000'000_i64, a, fractions_i64::nano );
355 test_to_num_of( 400'000'000_i64, b, fractions_i64::nano );
356 test_to_num_of( 10_i64, exp_sum, fractions_i64::seconds );
357 test_to_num_of( 10'800'000'000_i64, exp_sum, fractions_i64::nano );
358 }
359 {
360 fraction_i64 n1 ( 999'999'999_ns );
361 fraction_i64 n2 ( 999'999'999_ns );
362 fraction_i64 exp_nsum ( 1'999'999'998_ns );
363 REQUIRE( exp_nsum == n1 + n2 );
364 test_to_num_of( 999'999'999_i64, n1, fractions_i64::nano );
365 test_to_num_of( 1'999'999'998_i64, exp_nsum, fractions_i64::nano );
366 test_to_num_of( 999'999_i64, n1, fractions_i64::micro );
367 test_to_num_of( 1'999'999_i64, exp_nsum, fractions_i64::micro );
368 // OVERFLOW
369 test_to_num_of( 999'999'999'000_i64, n1, fractions_i64::pico, true /* overflow */ );
370 test_to_num_of( 1'999'999'998'000_i64, exp_nsum, fractions_i64::pico, true /* overflow */ );
371 }
372 { // OVERFLOW
373 // 1'000'000'000'000
374 // 999'999'999'999
375 // 1'999'999'999'998
376 fraction_i64 p1 ( 999'999'999'999_p );
377 // fraction_i64 p2 ( 999'999'999'999_p );
378 fraction_i64 exp_sum ( 1'999'999'999'998_p );
379 test_to_num_of( 999'999'999_i64, p1, fractions_i64::pico, true /* overflow */ );
380 test_to_num_of( 1'999'999'999'998_i64, exp_sum, fractions_i64::pico, true /* overflow */);
381 // REQUIRE( exp_sum == p1 + p2 );
382 }
383}
384
385TEST_CASE("Fraction String Test 01.2", "[integer][fraction][type][string]") {
386 {
387 fraction_i64 exp = 10_s;
388
389 const auto [a1, len1, ok1] = to_fraction_i64("10/1", 0_s, 365_d);
390 REQUIRE(true == ok1);
391 REQUIRE(exp == a1);
392 {
393 const auto [b, len, ok] = to_fraction_i64(a1.toString(), 0_s, 365_d);
394 REQUIRE(true == ok);
395 REQUIRE(exp == b);
396 }
397
398 const auto [a2, len2, ok2] = to_fraction_i64("10/1", 10_s, 10_s);
399 REQUIRE(true == ok2);
400 REQUIRE(exp == a2);
401 {
402 const auto [b, len, ok] = to_fraction_i64(a2.toString(), a2, a2);
403 REQUIRE(true == ok);
404 REQUIRE(exp == b);
405 }
406
407 REQUIRE(false == to_fraction_i64("10/1", 100_ns, 9_s).b);
408 REQUIRE(false == to_fraction_i64("10/1", 11_s, 365_d).b);
409 }
410 {
411 const auto [a1, len1, ok1] = to_fraction_i64(" 10 / 1000000 ", 0_s, 365_d);
412 REQUIRE(true == ok1);
413 REQUIRE(10_us == a1);
414 {
415 const auto [b, len, ok] = to_fraction_i64(a1.toString(), a1, a1);
416 REQUIRE(true == ok);
417 REQUIRE(10_us == b);
418 }
419
420 REQUIRE(false == to_fraction_i64(" 10x / 1000000 ", 0_s, 365_d).b);
421 REQUIRE(false == to_fraction_i64(" 10 / 1000000x ", 0_s, 365_d).b);
422 REQUIRE(false == to_fraction_i64(" 10 % 1000000x ", 0_s, 365_d).b);
423 REQUIRE(false == to_fraction_i64(" 10 ", 0_s, 365_d).b);
424 }
425}
426
427TEST_CASE( "Fraction Arithmetic Test 02", "[integer][fraction]" ) {
428 {
429 fraction<int> b(1, 6);
430 REQUIRE( b == fraction<int>(2, 12U));
431 }
432 {
433 fraction<int> b(6, 1);
434 REQUIRE( b == fraction<int>(12, 2U));
435 }
436 {
437 fraction<int> a(1, 4), b(1, 6);
438 fraction<int> exp_sum(5, 12);
439 fraction<int> exp_diff(1, 12);
440 fraction<int> exp_mul(1, 24);
441 fraction<int> exp_div(3, 2);
442 test_comp_fract(a, b, a, b, exp_sum, exp_diff, exp_mul, exp_div);
443 }
444 {
445 fraction<int> a(1, 4), b(6, 1);
446 fraction<int> exp_sum(25, 4);
447 fraction<int> exp_diff(-23, 4);
448 fraction<int> exp_mul(3, 2);
449 fraction<int> exp_div(1, 24);
450 test_comp_fract(a, b, b, a, exp_sum, exp_diff, exp_mul, exp_div);
451 }
452 {
453 fraction<int64_t> a(-1, 4), b(-1, 6);
454 fraction<int64_t> exp_sum(-5, 12);
455 fraction<int64_t> exp_diff(-1, 12);
456 fraction<int64_t> exp_mul(1, 24);
457 fraction<int64_t> exp_div(3, 2);
458 test_comp_fract(a, b, b, a, exp_sum, exp_diff, exp_mul, exp_div);
459 }
460 {
461 fraction<int> a(-1, 4), b(-1, 6);
462 fraction<int> exp_sum(-5, 12);
463 fraction<int> exp_diff(-1, 12);
464 fraction<int> exp_mul(1, 24);
465 fraction<int> exp_div(3, 2);
466 test_comp_fract(a, b, b, a, exp_sum, exp_diff, exp_mul, exp_div);
467 }
468 {
469 fraction<int> a(-1, 4), b( 1, 6);
470 fraction<int> exp_sum(-1, 12);
471 fraction<int> exp_diff(-5, 12);
472 fraction<int> exp_mul(-1, 24);
473 fraction<int> exp_div(-3, 2);
474 test_comp_fract(a, b, b, a, exp_sum, exp_diff, exp_mul, exp_div);
475 }
476 {
477 fraction<int> a(1, 4), b(-1, 6);
478 fraction<int> exp_sum(1, 12);
479 fraction<int> exp_diff(5, 12);
480 fraction<int> exp_mul(-1, 24);
481 fraction<int> exp_div(-3, 2);
482 test_comp_fract(a, b, a, b, exp_sum, exp_diff, exp_mul, exp_div);
483 }
484 {
485 // unsigned: micro + nano
486 fraction_u64 a(1, 1'000_u64), b(1, 1'000'000'000_u64);
487 fraction_u64 exp_sum( 1000001_u64, 100'0000'000_u64);
488 fraction_u64 exp_diff( 999999_u64, 1'000'000'000_u64);
489 fraction_u64 exp_mul( 1_u64, 1'000'000'000'000_u64);
490 fraction_u64 exp_div( 1000000_u64, 1_u64);
491 test_comp_fract(a, b, a, b, exp_sum, exp_diff, exp_mul, exp_div);
492 }
493 {
494 // signed: micro + nano
495 fraction_i64 a(1_m), b(1_n);
496 fraction_i64 exp_sum( 1000001_n);
497 fraction_i64 exp_diff( 999999_n);
498 fraction_i64 exp_mul( 1_p);
499 fraction_i64 exp_div( 1000000_one);
500 test_comp_fract(a, b, a, b, exp_sum, exp_diff, exp_mul, exp_div);
501 }
502 {
503 // signed: 100 micro + 1'000'000 nano
504 fraction_i64 a(100_i64*fractions_i64::milli), b(1'000'000_i64*fractions_i64::nano);
505 fraction_i64 exp_sum( 101_i64, 1'000_u64);
506 fraction_i64 exp_diff( 99_i64, 1'000_u64);
507 fraction_i64 exp_mul( 1_i64, 10'000_u64);
508 fraction_i64 exp_div( 100_i64, 1_u64);
509 test_comp_fract(a, b, a, b, exp_sum, exp_diff, exp_mul, exp_div);
510 }
511 {
512 const std::chrono::milliseconds::rep exp_count = 100;
513 const fraction<int64_t> a(static_cast<int64_t>(exp_count) * fractions_i64::milli);
514 test_duration(a, std::chrono::milliseconds::zero(), exp_count);
515 }
516 {
517 const std::chrono::nanoseconds::rep exp_count = -50;
518 const fraction_i64 a(static_cast<int64_t>(exp_count) * fractions_i64::nano);
519 test_duration(a, std::chrono::nanoseconds::zero(), exp_count);
520 }
521 {
522 const std::chrono::hours::rep exp_count = 24;
523 const fraction_i64 a(static_cast<int64_t>(exp_count) * fractions_i64::hours);
524 test_duration(a, std::chrono::hours::zero(), exp_count);
525 }
526 {
527 const fraction_i64 refresh_rate = 60_i64/1_s;
528 const fraction_i64 fps = 1_i64 / refresh_rate;
529 REQUIRE( 1_i64 / fps == refresh_rate );
530 REQUIRE( fps == 1_i64 / refresh_rate );
531 REQUIRE( 2_i64 * fps == 1_i64 / ( refresh_rate / 2_i64 ) );
532
533 REQUIRE( fractions_i64::milli / 2_i64 == 500_i64 * fractions_i64::micro );
534 REQUIRE( 1_m / 2_one == 500_one * 1_u );
535 REQUIRE( 1_i64 / fractions_i64::milli == fractions_i64::kilo );
536 REQUIRE( fractions_i64::milli/-1000_i64 == -fractions_i64::micro );
537 REQUIRE( 500_i64 * fractions_i64::milli == fractions_i64::seconds/2_i64 );
538 REQUIRE( 1000_ms == fractions_i64::seconds );
539 REQUIRE( 1_i64 * fractions_i64::seconds == 60_i64/fractions_i64::minutes );
540 REQUIRE( 60_s == fractions_i64::minutes );
541 REQUIRE( 60_s == 1_min );
542 REQUIRE( 60_i64 * fractions_i64::minutes == fractions_i64::hours );
543 REQUIRE( 24_i64 * fractions_i64::hours == fractions_i64::days );
544 REQUIRE( 24_h == 1_d );
545
546 const fraction_i64 m(720_i64 * fractions_i64::minutes); // 12 hours
547 const fraction_i64 h( 48_i64 * fractions_i64::hours);
548 const fraction_i64 d( 2_i64 * fractions_i64::days);
549 const fraction_i64 t = m + h + d;
550 REQUIRE( m == h/4_i64 );
551 REQUIRE( h == d );
552 REQUIRE( t > 4_i64 * fractions_i64::days );
553 }
554 {
555 fraction_i64 a ( 1'000l, 1lu ); // 1'000s
556 fraction_i64 b ( 1'000l, 1'000'000'000lu ); // 1'000ns
557 REQUIRE( 1000_s == a );
558 REQUIRE( 1000_ns == b );
559 fraction_i64 c = a + b;
560 fraction_i64 exp_c ( 1'000'000'000lu + 1lu, 1'000'000lu ); // 1'000ns
561 REQUIRE( exp_c == c );
562 }
563}
564
565/**
566 * Resembling the GNU/Linux bits/types.h,
567 * documenting whether time_t is 32-bit (arm-32) or 64-bit (arm-64, x86_64, ..).
568 */
569static int sizeof_time_t() {
570/* X32 kernel interface is 64-bit. */
571#if defined __x86_64__ && defined __ILP32__
572 // 64 bit size
573 #if __WORDSIZE == 32
574 return sizeof( __int64_t );
575 #else
576 return sizeof( long int );
577 #endif
578#else
579 // 32 bit or 64 bit
580 return sizeof( long int );
581#endif
582}
583
584/**
585 * Resembling the GNU/Linux bits/types.h,
586 * documenting whether tv_nsec of struct timespec is 32-bit (arm-32) or 64-bit (arm-64, x86_64, ..).
587 */
588static int sizeof_tv_nsec() {
589#if __WORDSIZE == 64 \
590 || (defined __SYSCALL_WORDSIZE && __SYSCALL_WORDSIZE == 64) \
591 || __TIMESIZE == 32
592 // 32 bit or 64 bit: __syscall_slong_t
593 return sizeof( int64_t );
594#else
595 // 32 bit or 64 bit
596 return sizeof( long int );
597#endif
598}
599
600TEST_CASE( "struct timespec type validation Test 03.00", "[fraction][struct_timespec][time]" ) {
601 // testing fraction_timespec::to_timespec()
602 {
603 using time_t_type = decltype(timespec::tv_sec);
604 INFO_STR(" tv_sec: sizeof=" + std::to_string( sizeof( time_t_type ) ) + ", signed " + std::to_string( std::is_signed_v<time_t_type>) );
605 CHECK( sizeof_time_t() == sizeof( time_t_type ) );
606 CHECK( true == std::is_signed_v<time_t_type> );
607
608 using ns_type = decltype(timespec::tv_nsec);
609 INFO_STR(" tv_nsec: sizeof=" + std::to_string( sizeof( ns_type ) ) + ", signed " + std::to_string( std::is_signed_v<ns_type>) );
610 CHECK( sizeof_tv_nsec() == sizeof( ns_type ) );
611 CHECK( true == std::is_signed_v<ns_type> );
612 }
613}
614
615
616TEST_CASE( "Fraction Time Arithmetic Add Test 03.1", "[fraction][fraction_timespec][add]" ) {
617 const int64_t ns_per_sec = 1'000'000'000_i64;
618
619 // 12.4 + 12.4 = 24.8 w/ double overflow in tv_nsec
620 {
621 fraction_timespec a ( 10_i64, 2 * ns_per_sec + 400000000_i64 );
622 fraction_timespec b ( 10_i64, 2 * ns_per_sec + 400000000_i64 );
623 fraction_timespec exp_sum ( 24_i64, 800000000_i64 );
624 INFO_STR(" a " + a.toString() );
625 INFO_STR(" b " + b.toString() );
626 INFO_STR(" a+b " + (a+b).toString() );
627 REQUIRE( ( a + b ) == exp_sum );
628 }
629 // 13.4 - 3.4 = 10.0 w/ double overflow in tv_nsec
630 {
631 fraction_timespec a ( 13_i64, 400000000_i64 );
632 fraction_timespec b ( 1_i64, 2 * ns_per_sec + 400000000_i64 );
633 fraction_timespec exp_sum ( 10_i64, 0_i64 );
634 INFO_STR(" a " + a.toString() );
635 INFO_STR(" b " + b.toString() );
636 INFO_STR(" a-b " + (a-b).toString() );
637 REQUIRE( ( a - b ) == exp_sum );
638 }
639 // 12.0 - 1.9 = 10.1 w/ double overflow in tv_nsec
640 {
641 fraction_timespec a ( 12_i64, 0_i64 );
642 fraction_timespec b ( 3_i64, -2 * ns_per_sec + 900000000_i64 );
643 fraction_timespec exp_sum ( 10_i64, 100000000_i64 );
644 INFO_STR(" a " + a.toString() );
645 INFO_STR(" b " + b.toString() );
646 INFO_STR(" a-b " + (a-b).toString() );
647 REQUIRE( ( a - b ) == exp_sum );
648 }
649 // 10.4 + 0.4 = 10.8
650 {
651 fraction_timespec a ( 10_i64, 400000000_i64 );
652 fraction_timespec b ( 0_i64, 400000000_i64 );
653 fraction_timespec exp_sum ( 10_i64, 800000000_i64 );
654 REQUIRE( ( a + b ) == exp_sum );
655 }
656 // 10.4 + 0.4 = 10.8
657 {
658 fraction_i64 a ( 10_s + 400_ms );
659 fraction_i64 b ( 0_s + 400_ms );
660 fraction_i64 exp_sum ( 10_s + 800_ms );
661 INFO_STR(" a " + a.toString() );
662 INFO_STR(" b " + b.toString() );
663 INFO_STR(" a+b " + (a+b).toString() );
664 REQUIRE( ( a + b ) == exp_sum );
665 }
666 // 10.4 + 0.4 = 10.8
667 {
668 fraction_timespec a ( 10_s + 400_ms );
669 fraction_timespec b ( 0_s + 400_ms );
670 fraction_timespec exp_sum ( 10_s + 800_ms );
671 INFO_STR(" a " + a.toString() );
672 INFO_STR(" b " + b.toString() );
673 INFO_STR(" a+b " + (a+b).toString() );
674 REQUIRE( ( a + b ) == exp_sum );
675 }
676 // 10.4 + 0.7 = 11.1
677 {
678 fraction_timespec a { 10_s + 400_ms };
679 fraction_timespec b { 0_s + 700_ms };
680 fraction_timespec exp_sum { 11_s + 100_ms };
681 INFO_STR(" a " + a.toString() );
682 INFO_STR(" b " + b.toString() );
683 INFO_STR(" a+b " + (a+b).toString() );
684 REQUIRE( ( a + b ) == exp_sum );
685 }
686 // 10.4 + 2.7 (in denominator) = 13.1
687 {
688 fraction_timespec a { 10_s + 400_ms };
689 fraction_timespec b { 0_s + 2700_ms };
690 fraction_timespec exp_sum { 13_s + 100_ms };
691 INFO_STR(" a " + a.toString() );
692 INFO_STR(" b " + b.toString() );
693 INFO_STR(" a+b " + (a+b).toString() );
694 REQUIRE( ( a + b ) == exp_sum );
695 }
696 // 10.4 + -0.3 = 10.1
697 {
698 fraction_timespec a { 10_s + 400_ms };
699 fraction_timespec b { 0_s + -300_ms };
700 fraction_timespec exp_sum { 10_s + 100_ms };
701 REQUIRE( ( a + b ) == exp_sum );
702 }
703 // 10.-3 + 0.4 = 10.1
704 {
705 fraction_timespec a { 10_s + -300_ms };
706 fraction_timespec b { 0_s + 400_ms };
707 fraction_timespec exp_sum { 10_s + 100_ms };
708 REQUIRE( ( a + b ) == exp_sum );
709 }
710 // 10.4 + -0.9 = 9.5
711 {
712 fraction_timespec a { 10_s + 400_ms };
713 fraction_timespec b { 0_s + -900_ms };
714 fraction_timespec exp_sum { 9_s + 500_ms };
715 INFO_STR(" a " + a.toString() );
716 INFO_STR(" b " + b.toString() );
717 INFO_STR(" a+b " + (a+b).toString() );
718 REQUIRE( ( a + b ) == exp_sum );
719 }
720 // 10.4 + -2.7 = 7.7
721 {
722 fraction_timespec a { 10_s + 400_ms };
723 fraction_timespec b { 0_s + -2700_ms };
724 fraction_timespec exp_sum { 7_s + 700_ms };
725 INFO_STR(" a " + a.toString() );
726 INFO_STR(" b " + b.toString() );
727 INFO_STR(" a+b " + (a+b).toString() );
728 REQUIRE( ( a + b ) == exp_sum );
729 }
730 // 10.-9 + 0.4 = 9.5
731 {
732 fraction_timespec a { 10_s + -900_ms };
733 fraction_timespec b { 0_s + 400_ms };
734 fraction_timespec exp_sum { 9_s + 500_ms };
735 INFO_STR(" a " + a.toString() );
736 INFO_STR(" b " + b.toString() );
737 INFO_STR(" a+b " + (a+b).toString() );
738 REQUIRE( ( a + b ) == exp_sum );
739 }
740}
741
742TEST_CASE( "Fraction Time Arithmetic Sub Test 03.2", "[fraction][fraction_timespec][sub]" ) {
743 // normalize tests
744 // normalize: 1 s + 4*1000000000 ns = 5s
745 {
746 fraction_timespec a( 1, 4000000000_i64 );
747 INFO_STR(" a " + a.toString() );
748 REQUIRE( a.tv_sec == 5 );
749 REQUIRE( a.tv_nsec == 0_i64 );
750 }
751 // normalize: -1 s - 4*1000000000 ns = -5s
752 {
753 fraction_timespec a( -1, -4000000000_i64 );
754 INFO_STR(" a " + a.toString() );
755 REQUIRE( a.tv_sec == -5 );
756 REQUIRE( a.tv_nsec == 0_i64 );
757 }
758 // normalize: -1 s + 4*1000000000 ns = 3s
759 {
760 fraction_timespec a( -1, 4000000000_i64 );
761 INFO_STR(" a " + a.toString() );
762 REQUIRE( a.tv_sec == 3 );
763 REQUIRE( a.tv_nsec == 0_i64 );
764 }
765 // normalize: 1 - 0.4 = 0.6
766 {
767 fraction_timespec a( 1, -400000000_i64 );
768 INFO_STR(" a " + a.toString() );
769 REQUIRE( a.tv_sec == 0 );
770 REQUIRE( a.tv_nsec == 600000000_i64 );
771 }
772 // normalize: -1 + 0.4 = -0.6
773 {
774 fraction_timespec a( -1, +400000000_i64 );
775 INFO_STR(" a " + a.toString() );
776 REQUIRE( a.tv_sec == 0 );
777 REQUIRE( a.tv_nsec == -600000000_i64 );
778 }
779 // 674.0 - 675.547 = -1.547
780 {
781 fraction_timespec a( 674, 0 );
782 fraction_timespec b( 675, 547000000_i64 );
783 fraction_timespec exp_sum( -1, -547000000_i64 );
784 INFO_STR(" a " + a.toString() );
785 INFO_STR(" b " + b.toString() );
786 INFO_STR(" exp " + exp_sum.toString() );
787 INFO_STR(" a-b " + (a-b).toString() );
788 REQUIRE( ( a - b ) == exp_sum );
789 }
790 // 674.0 - 675.547 = -1.547
791 {
792 fraction_timespec a { 674_s + 0_ms };
793 fraction_timespec b { 675_s + 547_ms };
794 fraction_timespec exp_sum { -1_s - 547_ms };
795 INFO_STR(" a " + a.toString() );
796 INFO_STR(" b " + b.toString() );
797 INFO_STR(" exp " + exp_sum.toString() );
798 INFO_STR(" a-b " + (a-b).toString() );
799 REQUIRE( ( a - b ) == exp_sum );
800 }
801 // 10.4 - 0.3 = 10.1
802 {
803 fraction_timespec a ( 10_i64, 400000000_i64 );
804 fraction_timespec b ( 0_i64, 300000000_i64 );
805 fraction_timespec exp_sum ( 10_i64, 100000000_i64 );
806 REQUIRE( ( a - b ) == exp_sum );
807 }
808 // 10.4 - 0.3 = 10.1
809 {
810 fraction_timespec a ( 10_s + 400_ms );
811 fraction_timespec b ( 0_s + 300_ms );
812 fraction_timespec exp_sum ( 10_s + 100_ms );
813 REQUIRE( ( a - b ) == exp_sum );
814 }
815 // 10.4 - 0.7 = 9.7
816 {
817 fraction_timespec a { 10_s + 400_ms };
818 fraction_timespec b { 0_s + 700_ms };
819 fraction_timespec exp_sum { 9_s + 700_ms };
820 INFO_STR(" a " + a.toString() );
821 INFO_STR(" b " + b.toString() );
822 INFO_STR(" a-b " + (a-b).toString() );
823 REQUIRE( ( a - b ) == exp_sum );
824 }
825 // 10.4 - 2.7 (in denominator) = 7.7
826 {
827 fraction_timespec a { 10_s + 400_ms };
828 fraction_timespec b { 0_s + 2700_ms };
829 fraction_timespec exp_sum { 7_s + 700_ms };
830 INFO_STR(" a " + a.toString() );
831 INFO_STR(" b " + b.toString() );
832 INFO_STR(" a-b " + (a-b).toString() );
833 REQUIRE( ( a - b ) == exp_sum );
834 }
835
836 // 10.4 - -0.3 = 10.7
837 {
838 fraction_timespec a { 10_s + 400_ms };
839 fraction_timespec b { 0_s + -300_ms };
840 fraction_timespec exp_sum { 10_s + 700_ms };
841 REQUIRE( ( a - b ) == exp_sum );
842 }
843 // 10.-2 - 0.4 = 9.4
844 {
845 fraction_timespec a { 10_s + -200_ms };
846 fraction_timespec b { 0_s + 400_ms };
847 fraction_timespec exp_sum { 9_s + 400_ms };
848 INFO_STR(" a " + a.toString() );
849 INFO_STR(" b " + b.toString() );
850 INFO_STR(" a-b " + (a-b).toString() );
851 REQUIRE( ( a - b ) == exp_sum );
852 }
853 // 10.4 - -0.9 = 11.3
854 {
855 fraction_timespec a { 10_s + 400_ms };
856 fraction_timespec b { 0_s + -900_ms };
857 fraction_timespec exp_sum { 11_s + 300_ms };
858 INFO_STR(" a " + a.toString() );
859 INFO_STR(" b " + b.toString() );
860 INFO_STR(" a-b " + (a-b).toString() );
861 REQUIRE( ( a - b ) == exp_sum );
862 }
863 // 10.-9 - 0.4 = 8.7
864 {
865 fraction_timespec a { 10_s + -900_ms };
866 fraction_timespec b { 0_s + 400_ms };
867 fraction_timespec exp_sum { 8_s + 700_ms };
868 INFO_STR(" a " + a.toString() );
869 INFO_STR(" b " + b.toString() );
870 INFO_STR(" a-b " + (a-b).toString() );
871 REQUIRE( ( a - b ) == exp_sum );
872 }
873}
874
875TEST_CASE( "Fraction Time Measurement Test 04.01", "[fraction][fraction_timespec][time]" ) {
876 const int64_t sleep_ms = 50;
877 //
878 // Ideally we assume accuracy of at least 1/2 millisecond, hence the difference shall not be greater
879 // const fraction_i64 accuracy = fractions_i64::milli*2_i64/3_i64;
880 // However, running within virtual machines etc, we have to be more generous here: 60_ms
881 // Detected using KVM on GNU/Linux host for FreeBSD 13.1 target
882 const fraction_i64 accuracy = fractions_i64::milli*60_i64;
883 //
884 {
886 sleep_for( sleep_ms * 1_ms );
888 const fraction_timespec td_1 = t1 - t0;
889 const fraction_i64 td_2 = td_1.to_fraction_i64();
890 const fraction_i64 terr = abs( td_2 - fractions_i64::milli * sleep_ms );
891 INFO_STR( " Test-1: sleep_for() getMonotonicTime:");
892 INFO_STR( " - t0 " + t0.toString() );
893 INFO_STR( " - t1 " + t1.toString() );
894 INFO_STR( " - td_1 " + td_1.toString() );
895 INFO_STR( " - td_2 " + td_2.toString(true) + ", " + std::to_string( td_2.to_num_of(1_ms) ) + "ms, err " + terr.toString(true) + " <?= " + accuracy.toString(true) );
896 REQUIRE( t0.tv_sec >= 0 );
897 REQUIRE( t0.tv_nsec >= 0 );
898 REQUIRE( t1.tv_sec >= 0 );
899 REQUIRE( t1.tv_nsec >= 0 );
900 REQUIRE( td_1.tv_sec >= 0 );
901 REQUIRE( td_1.tv_nsec >= 0 );
902 REQUIRE( td_2 >= fractions_i64::zero );
903 // Check accuracy
904 REQUIRE( terr <= accuracy );
905 }
906 {
908 sleep_until( t0 + fraction_timespec( sleep_ms * 1_ms ) );
910 const fraction_timespec td_1 = t1 - t0;
911 const fraction_i64 td_2 = td_1.to_fraction_i64();
912 const fraction_i64 terr = abs( td_2 - fractions_i64::milli * sleep_ms );
913 INFO_STR( " Test-2: sleep_until() getMonotonicTime:");
914 INFO_STR( " - t0 " + t0.toString() );
915 INFO_STR( " - t1 " + t1.toString() );
916 INFO_STR( " - td_1 " + td_1.toString() );
917 INFO_STR( " - td_2 " + td_2.toString(true) + ", " + std::to_string( td_2.to_num_of(1_ms) ) + "ms, err " + terr.toString(true) + " <?= " + accuracy.toString(true) );
918 REQUIRE( t0.tv_sec >= 0 );
919 REQUIRE( t0.tv_nsec >= 0 );
920 REQUIRE( t1.tv_sec >= 0 );
921 REQUIRE( t1.tv_nsec >= 0 );
922 REQUIRE( td_1.tv_sec >= 0 );
923 REQUIRE( td_1.tv_nsec >= 0 );
924 REQUIRE( td_2 >= fractions_i64::zero );
925 // Check accuracy
926 REQUIRE( terr <= accuracy );
927 }
928}
929
930TEST_CASE( "Fraction Time Conversion Test 05.01", "[fraction_timespec][time]" ) {
932 fraction_timespec onesec(1, 0);
933 fraction_timespec onesec_onemilli(1, 100000000_i64);
934 {
936 jau::INFO_PRINT( "a - 1968-1-1 -> %s, %s", t0.toString().c_str(), t0.toISO8601String().c_str());
937 REQUIRE(zero > t0);
938 }
939 {
941 jau::INFO_PRINT( "a - 1970-1-1 -> %s, %s", t0.toString().c_str(), t0.toISO8601String().c_str());
942 REQUIRE(zero == t0);
943 }
944 {
945 fraction_timespec exp(24_i64*3600_i64, 0);
947 jau::INFO_PRINT( "a - 1970-1-2 -> %s, %s", t0.toString().c_str(), t0.toISO8601String().c_str());
948 REQUIRE(exp == t0);
949 }
950 {
952 jau::INFO_PRINT( "a - 2024-1-1 -> %s, %s", t0.toString().c_str(), t0.toISO8601String().c_str());
953 }
954 {
955 int64_t utcOffsetSec; size_t consumedChars;
956 fraction_timespec t00 = fraction_timespec::from("2024-1-1", utcOffsetSec, consumedChars);
957 REQUIRE(0 == utcOffsetSec); REQUIRE( 8 == consumedChars);
958 REQUIRE(t00 == fraction_timespec::from("2024-1-1"));
959 fraction_timespec t00a = fraction_timespec::from("2024-01-01T00:00:01Z", utcOffsetSec, consumedChars);
960 REQUIRE(0 == utcOffsetSec); REQUIRE(20 == consumedChars);
961 REQUIRE(t00a == fraction_timespec::from("2024-01-01T00:00:01Z"));
962 fraction_timespec t00b = fraction_timespec::from("2024-01-01T00:00:01.1Z", utcOffsetSec, consumedChars);
963 REQUIRE(0 == utcOffsetSec); REQUIRE(22 == consumedChars);
964 REQUIRE(t00b == fraction_timespec::from("2024-01-01T00:00:01.1Z"));
965 fraction_timespec t01 = fraction_timespec::from("2024-01-01T12:34:56Z", utcOffsetSec, consumedChars);
966 REQUIRE(0 == utcOffsetSec); REQUIRE(20 == consumedChars);
967 REQUIRE(t01 == fraction_timespec::from("2024-01-01T12:34:56Z"));
968 fraction_timespec t02 = fraction_timespec::from("2024-01-01T12:34:56.789Z", utcOffsetSec, consumedChars);
969 REQUIRE(0 == utcOffsetSec); REQUIRE(24 == consumedChars);
970 REQUIRE(t02 == fraction_timespec::from("2024-01-01T12:34:56.789Z"));
971 fraction_timespec t03 = fraction_timespec::from("2024-01-01 12:34:56", utcOffsetSec, consumedChars);
972 REQUIRE(0 == utcOffsetSec); REQUIRE(19 == consumedChars);
973 REQUIRE(t03 == fraction_timespec::from("2024-01-01 12:34:56"));
974 fraction_timespec t04 = fraction_timespec::from("2024-01-01 12:34:56.789", utcOffsetSec, consumedChars);
975 REQUIRE(0 == utcOffsetSec); REQUIRE(24 == consumedChars);
976 REQUIRE(t04 == fraction_timespec::from("2024-01-01 12:34:56.789"));
977
978 jau::INFO_PRINT( "b - t00 %s, %s", t00.toString().c_str(), t00.toISO8601String().c_str());
979 jau::INFO_PRINT( "b - t00 %s, %s", t00.toString().c_str(), t00.toISO8601String(true).c_str());
980 jau::INFO_PRINT( "b - t01 %s, %s", t01.toString().c_str(), t01.toISO8601String().c_str());
981 jau::INFO_PRINT( "b - t01 %s, %s", t01.toString().c_str(), t01.toISO8601String(true).c_str());
982 jau::INFO_PRINT( "b - t02 %s, %s", t02.toString().c_str(), t02.toISO8601String().c_str());
983 jau::INFO_PRINT( "b - t02 %s, %s", t02.toString().c_str(), t02.toISO8601String(true).c_str());
984 jau::INFO_PRINT( "b - t03 %s, %s", t03.toString().c_str(), t03.toISO8601String(true).c_str());
985 jau::INFO_PRINT( "b - t04 %s, %s", t04.toString().c_str(), t04.toISO8601String(true).c_str());
986 jau::INFO_PRINT( "b - t04 %s, %s", t04.toString().c_str(), t04.toISO8601String(true, true).c_str());
987
989 fraction_timespec tX1 = fraction_timespec::from(2024, 1, 1, 12, 34, 56, 0);
990 fraction_timespec tX2 = fraction_timespec::from(2024, 1, 1, 12, 34, 56, 789000000_u64);
991 REQUIRE(tX0 == t00);
992 REQUIRE(tX1 == t01);
993 REQUIRE(tX1 == t03);
994 REQUIRE(tX2 == t02);
995 REQUIRE(tX2 == t04);
996 REQUIRE(t00a - onesec == t00);
997 REQUIRE(t00b - onesec_onemilli == t00);
998
999 REQUIRE(tX0 == fraction_timespec::from(tX0.toISO8601String()));
1000 REQUIRE(tX1 == fraction_timespec::from(tX1.toISO8601String()));
1001 jau::INFO_PRINT( "c - tX2 %s, %s", tX2.toString().c_str(), tX2.toISO8601String().c_str());
1002 jau::INFO_PRINT( "c - tX2 %s, %s", tX2.toString().c_str(), tX2.toISO8601String(true).c_str());
1003 REQUIRE(tX2 == fraction_timespec::from(tX2.toISO8601String()));
1004 REQUIRE(tX0 == fraction_timespec::from(tX0.toISO8601String(true)));
1005 REQUIRE(tX1 == fraction_timespec::from(tX1.toISO8601String(true)));
1006 REQUIRE(tX2 == fraction_timespec::from(tX2.toISO8601String(true)));
1007 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T"));
1008 REQUIRE(tX0 == fraction_timespec::from("2024-01-01Z"));
1009 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T00:00:00"));
1010 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00"));
1011 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00.0"));
1012 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00.00"));
1013 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00.0Z"));
1014 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00.00Z"));
1015 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T00:00:00Z"));
1016 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00Z"));
1017 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T00:00:00.00Z"));
1018 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 00:00:00.0Z"));
1019
1020 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.789"));
1021 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.7890"));
1022 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.78900"));
1023 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.789Z"));
1024 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.7890Z"));
1025 REQUIRE(tX2 == fraction_timespec::from("2024-01-01 12:34:56.78900Z"));
1026 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.789"));
1027 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.7890"));
1028 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.78900"));
1029 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.789Z"));
1030 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.7890Z"));
1031 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T12:34:56.78900Z"));
1032 }
1033 {
1034 fraction_timespec p1h(60*60_i64, 0);
1035 fraction_timespec p2m( 2*60_i64, 0);
1036 fraction_timespec tX0 = fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64);
1037 fraction_timespec tX1 = fraction_timespec::from(2024, 1, 1, 2, 4, 3, 456789000_i64);
1038 fraction_timespec tX2 = fraction_timespec::from(2024, 1, 1, 0, 0, 3, 456789000_i64);
1039 REQUIRE(tX0 + p1h + p2m == tX1);
1040 REQUIRE(tX0 - p1h - p2m == tX2);
1041
1042 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T01:02:03.456789+00:00"));
1043 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T01:02:03.456789+00:00", Bool::True));
1044 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T01:02:03.456789+01:02"));
1045
1046 if ( false ) {
1047 int64_t t0_offset; size_t consumedChars;
1048 fraction_timespec t0 = fraction_timespec::from("2024-01-01T01:02:03.456789+01:02", t0_offset, consumedChars);
1049 jau::INFO_PRINT( "d - 1t0 %s, %s, offset %" PRId64 "s, chars %zu", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset, consumedChars);
1050 fraction_timespec t1 = fraction_timespec::from("2024-01-01T01:02:03.456789+01:02", Bool::True);
1051 jau::INFO_PRINT( "d - 1t1 %s, %s", t1.toString().c_str(), t1.toISO8601String().c_str());
1052 }
1053 REQUIRE(tX0+p1h+p2m == fraction_timespec::from("2024-01-01T01:02:03.456789+01:02", Bool::True));
1054 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T01:02:03.456789-01:02"));
1055 REQUIRE(tX0-p1h-p2m == fraction_timespec::from("2024-01-01T01:02:03.456789-01:02", Bool::True));
1056
1057 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+00:00"));
1058 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+00:00", Bool::True));
1059 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+01:02"));
1060 REQUIRE(tX0+p1h+p2m == fraction_timespec::from("2024-01-01 01:02:03.456789+01:02", Bool::True));
1061 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789-01:02"));
1062 REQUIRE(tX0-p1h-p2m == fraction_timespec::from("2024-01-01 01:02:03.456789-01:02", Bool::True));
1063
1064 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+0000"));
1065 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+0000", Bool::True));
1066 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+0102"));
1067 REQUIRE(tX0+p1h+p2m == fraction_timespec::from("2024-01-01 01:02:03.456789+0102", Bool::True));
1068 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789-0102"));
1069 REQUIRE(tX0-p1h-p2m == fraction_timespec::from("2024-01-01 01:02:03.456789-0102", Bool::True));
1070
1071 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789 +0000"));
1072 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789 +0000", Bool::True));
1073 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789 +0102"));
1074 REQUIRE(tX0+p1h+p2m == fraction_timespec::from("2024-01-01 01:02:03.456789 +0102", Bool::True));
1075 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789 -0102"));
1076 REQUIRE(tX0-p1h-p2m == fraction_timespec::from("2024-01-01 01:02:03.456789 -0102", Bool::True));
1077
1078 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+00"));
1079 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+00", Bool::True));
1080 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789+01"));
1081 REQUIRE(tX0+p1h == fraction_timespec::from("2024-01-01 01:02:03.456789+01", Bool::True));
1082 REQUIRE(tX0 == fraction_timespec::from("2024-01-01 01:02:03.456789-01"));
1083 REQUIRE(tX0-p1h == fraction_timespec::from("2024-01-01 01:02:03.456789-01", Bool::True));
1084
1085
1086 REQUIRE(tX0 == fraction_timespec::from(tX0.toISO8601String()));
1087 REQUIRE(tX1 == fraction_timespec::from(tX1.toISO8601String()));
1088 REQUIRE(tX2 == fraction_timespec::from(tX2.toISO8601String()));
1089 REQUIRE(tX0 == fraction_timespec::from(tX0.toISO8601String(true)));
1090 REQUIRE(tX1 == fraction_timespec::from(tX1.toISO8601String(true)));
1091 REQUIRE(tX2 == fraction_timespec::from(tX2.toISO8601String(true)));
1092
1093 REQUIRE(tX0 == fraction_timespec::from("2024-01-01T01:02:03.456789+00:00", Bool::True));
1094 REQUIRE(tX1 == fraction_timespec::from("2024-01-01T01:02:03.456789+01:02", Bool::True));
1095 REQUIRE(tX2 == fraction_timespec::from("2024-01-01T01:02:03.456789-01:02", Bool::True));
1096 }
1097 {
1098 fraction_timespec tX0 = fraction_timespec::from(1, 2, 3, 4, 5, 6, 456789000_i64);
1099 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1100 fraction_timespec t0 = fraction_timespec::from("1-02-3T4:05:6.456789Z", t0_offset, consumedChars);
1101 jau::INFO_PRINT( "e - 0t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1102 REQUIRE(tX0 == t0);
1103 REQUIRE(0 == t0_offset);
1104 REQUIRE(21 == consumedChars);
1105 REQUIRE(tX0 == fraction_timespec::from("1-02-3T4:05:6.456789Z"));
1106 }
1107 {
1108 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1109 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789+01:02", t0_offset, consumedChars);
1110 jau::INFO_PRINT( "e - 1t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1111 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1112 REQUIRE(t0_offset == 60*60_i64 + 2*60_i64);
1113 REQUIRE(32 == consumedChars);
1114 }
1115 {
1116 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1117 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789-01:02", t0_offset, consumedChars);
1118 jau::INFO_PRINT( "e - 2t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1119 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1120 REQUIRE(t0_offset == -60*60_i64 - 2*60_i64);
1121 REQUIRE(32 == consumedChars);
1122 }
1123 {
1124 // early Z after y-m-d
1125 fraction_timespec tX0 = fraction_timespec::from(1, 2, 3, 0, 0, 0, 0_i64);
1126 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1127 fraction_timespec t0 = fraction_timespec::from("1-02-3Z4:05:6.456789+01:02", t0_offset, consumedChars);
1128 jau::INFO_PRINT( "e - 3t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1129 REQUIRE(tX0 == t0);
1130 REQUIRE(0 == t0_offset);
1131 REQUIRE(7 == consumedChars);
1132 }
1133 {
1134 // early Z after y-m-d h:m:s
1135 fraction_timespec tX0 = fraction_timespec::from(1, 2, 3, 4, 5, 6, 0_i64);
1136 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1137 fraction_timespec t0 = fraction_timespec::from("1-02-3T4:05:6Z.456789+01:02", t0_offset, consumedChars);
1138 jau::INFO_PRINT( "e - 4t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1139 REQUIRE(tX0 == t0);
1140 REQUIRE(0 == t0_offset);
1141 REQUIRE(14 == consumedChars);
1142 }
1143 {
1144 // early Z after y-m-d h:m:s.fs
1145 fraction_timespec tX0 = fraction_timespec::from(1, 2, 3, 4, 5, 6, 456789000_i64);
1146 int64_t t0_offset=987654321_i64; size_t consumedChars=2783964772;
1147 fraction_timespec t0 = fraction_timespec::from("1-02-3T4:05:6.456789Z+01:02", t0_offset, consumedChars);
1148 jau::INFO_PRINT( "e - 5t0 %s, %s, offset %" PRId64 "s", t0.toString().c_str(), t0.toISO8601String().c_str(), t0_offset);
1149 REQUIRE(tX0 == t0);
1150 REQUIRE(0 == t0_offset);
1151 REQUIRE(21 == consumedChars);
1152 }
1153 {
1154 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1155 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789 +01:02HALLO SJKSJSJKSJ", offset, consumedChars);
1156 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1157 REQUIRE(offset == 60*60_i64 + 2*60_i64);
1158 REQUIRE(39 == consumedChars);
1159 }
1160 {
1161 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1162 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789 +0102HALLO SJKSJSJKSJ", offset, consumedChars);
1163 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1164 REQUIRE(offset == 60*60_i64 + 2*60_i64);
1165 REQUIRE(38 == consumedChars);
1166 }
1167 {
1168 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1169 fraction_timespec t0 = fraction_timespec::from("Error01 2024-01-01 01:02:03.456789 +01:02HALLO SJKSJSJKSJ", offset, consumedChars);
1170 jau::INFO_PRINT( "Error01 t0 %s, %s", t0.toString().c_str(), t0.toISO8601String().c_str());
1171 REQUIRE(fraction_timespec() == t0);
1172 REQUIRE(true == t0.isZero());
1173 REQUIRE(offset == 0);
1174 REQUIRE(0 == consumedChars);
1175 }
1176 {
1177 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1178 fraction_timespec t0 = fraction_timespec::from("2024-EEE01-01 01:02:03.456789 +01:02HALLO SJKSJSJKSJ", offset, consumedChars);
1179 REQUIRE(true == t0.isZero());
1180 REQUIRE(offset == 0);
1181 REQUIRE(0 == consumedChars);
1182 }
1183 {
1184 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1185 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789 Ooops +01:02HALLO SJKSJSJKSJ", offset, consumedChars);
1186 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1187 REQUIRE(offset == 0);
1188 REQUIRE(30 == consumedChars);
1189 }
1190 {
1191 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1192 fraction_timespec t0 = fraction_timespec::from("2024-01-01 Ooops 01:02:03.456789 +01:02HALLO SJKSJSJKSJ", offset, consumedChars);
1193 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 0, 0, 0, 0_i64));
1194 REQUIRE(offset == 0);
1195 REQUIRE(10 == consumedChars);
1196 }
1197 {
1198 int64_t offset=987654321_i64; size_t consumedChars=2783964772;
1199 fraction_timespec t0 = fraction_timespec::from("2024-01-01 01:02:03.456789 +01Ooops:02HALLO SJKSJSJKSJ", offset, consumedChars);
1200 REQUIRE(t0 == fraction_timespec::from(2024, 1, 1, 1, 2, 3, 456789000_i64));
1201 REQUIRE(offset == 60*60_i64);
1202 REQUIRE(36 == consumedChars);
1203 }
1204
1205}
Fraction template type using integral values, evaluated at runtime.
uint_type denom
Denominator, always positive.
int_type num
Numerator, carries the sign.
constexpr double to_double() const noexcept
Returns the converted fraction to lossy double.
constexpr int_type to_num_of(const fraction< int_type > &new_base, bool *overflow_ptr=nullptr) const noexcept
Converts this this fraction to a numerator for the given new base fraction.
std::string toString(const bool show_double=false) const noexcept
Returns a string representation of this fraction.
std::chrono::duration< Rep, Period > to_duration(const std::chrono::duration< Rep, Period > &dur_ref, bool *overflow_ptr=nullptr) const noexcept
Convert this fraction into std::chrono::duration with given Rep and Period.
ordered_atomic< jau::fraction_i64, std::memory_order_seq_cst > sc_atomic_fraction_i64
SC atomic integral scalar jau::fraction_i64.
fraction< uint64_t > fraction_u64
fraction using uint64_t as integral type
fraction_timespec getMonotonicTime() noexcept
Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.
FracI64SizeBoolTuple to_fraction_i64(const std::string &value, const fraction_i64 &min_allowed, const fraction_i64 &max_allowed) noexcept
Returns the fraction_i64 of the given string in format <num>/<denom>, which may contain whitespace.
fraction< int64_t > fraction_i64
fraction using int64_t as integral type
constexpr T gcd(T a, T b) noexcept
Returns the greatest common divisor (GCD) of the two given integer values following Euclid's algorith...
Definition int_math.hpp:370
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 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 T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
constexpr const jau::fraction_i64 tera(1 '000 '000 '000 '000l, 1lu)
tera is 10^12
constexpr const jau::fraction_i64 zero(0l, 1lu)
zero is 0/1
constexpr const jau::fraction_i64 minutes(60l, 1lu)
minutes is 60/1
constexpr const jau::fraction_i64 nano(1l, 1 '000 '000 '000lu)
nano is 10^-9
constexpr const jau::fraction_i64 milli(1l, 1 '000lu)
milli is 10^-3
constexpr const jau::fraction_i64 seconds(1l, 1lu)
seconds is 1/1
constexpr const jau::fraction_i64 kilo(1 '000l, 1lu)
kilo is 10^3
constexpr const jau::fraction_i64 pico(1l, 1 '000 '000 '000 '000lu)
pico is 10^-12
constexpr const jau::fraction_i64 one(1l, 1lu)
one is 10^0 or 1/1
constexpr const jau::fraction_i64 days(86 '400l, 1lu)
days is 86400/1
constexpr const jau::fraction_i64 giga(1 '000 '000 '000l, 1lu)
giga is 10^9
constexpr const jau::fraction_i64 micro(1l, 1 '000 '000lu)
micro is 10^-6
constexpr const jau::fraction_i64 mega(1 '000 '000l, 1lu)
mega is 10^6
constexpr const jau::fraction_i64 hours(3 '600l, 1lu)
hours is 3660/1
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
Definition debug.cpp:254
bool sleep_until(const fraction_timespec &absolute_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_until causes the current thread to block until the specific time is reached.
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
bool sleep_for(const fraction_timespec &relative_time, const bool monotonic=true, const bool ignore_irq=true) noexcept
sleep_for causes the current thread to block until a specific amount of time has passed.
Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...
constexpr bool isZero() noexcept
int64_t tv_nsec
Nanoseconds component with its absolute value in range [0..1'000'000'000[ or [0..1'000'000'000).
int64_t tv_sec
Seconds component, with its absolute value in range [0..inf[ or [0..inf).
std::string toISO8601String(bool space_separator=false, bool muteTime=false) const noexcept
Convenience string conversion interpreted since Unix Epoch in UTC to ISO 8601 YYYY-mm-ddTHH:MM:SS....
constexpr fraction_i64 to_fraction_i64() const noexcept
Returns the sum of both components.
static fraction_timespec from(const std::string &datestr, int64_t &utcOffsetSec, size_t &consumedChars) noexcept
Conversion constructor from an ISO8601 time string, as produced via to_iso8601_string().
std::string toString() const noexcept
Return simple string representation in seconds and nanoseconds.
static void test_comp_fract(const fraction< int_type > &a, const fraction< int_type > &b, const fraction< int_type > &exp_max, const fraction< int_type > &exp_min, const fraction< int_type > &exp_sum, const fraction< int_type > &exp_diff, const fraction< int_type > &exp_mul, const fraction< int_type > &exp_div)
static void test_to_num_of(const int64_t exp, const fraction< int64_t > &v, const fraction< int64_t > &new_base, bool exp_overflow=false) noexcept
static int sizeof_time_t()
Resembling the GNU/Linux bits/types.h, documenting whether time_t is 32-bit (arm-32) or 64-bit (arm-6...
static void test_gcd_fract_pm(const int_type n, const std::make_unsigned_t< int_type > d, const int_type exp_gcd, const int_type exp_num, const std::make_unsigned_t< int_type > exp_denom)
static void test_gcd_fract(const int_type n, const std::make_unsigned_t< int_type > d, const int_type exp_gcd, const int_type exp_num, const std::make_unsigned_t< int_type > exp_denom)
TEST_CASE("Fraction Types Test 00", "[fraction][type]")
static int sizeof_tv_nsec()
Resembling the GNU/Linux bits/types.h, documenting whether tv_nsec of struct timespec is 32-bit (arm-...
static void test_duration(const fraction< int_type > &a, const std::chrono::duration< Rep, Period > &dur_ref, const Rep exp_count)