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