{"id":1049,"date":"2022-05-29T20:48:35","date_gmt":"2022-05-30T00:48:35","guid":{"rendered":"https:\/\/jausoft.com\/blog\/?p=1049"},"modified":"2022-05-30T02:39:00","modified_gmt":"2022-05-30T06:39:00","slug":"rational-expression-with-frictionless-fractions-and-implemented-time-in-cpp","status":"publish","type":"post","link":"https:\/\/jausoft.com\/blog\/2022\/05\/29\/rational-expression-with-frictionless-fractions-and-implemented-time-in-cpp\/","title":{"rendered":"Rational Expressions with frictionless Fractions and implemented Time"},"content":{"rendered":"<p>Natural numbers are defined as the sequence of numbers fully defined by their <em>initial value, <\/em>its successor and the successor of its successor and so forth. Despite the beauty of their intrinsic <em><a href=\"https:\/\/mathcs.clarku.edu\/~djoyce\/numbers\/peano.pdf\">Dedekind\u2013Peano axioms<\/a>,<\/em> they are also fully proven by induction.<\/p>\n<p><img decoding=\"async\" class=\"mwe-math-fallback-image-inline\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/7796d97ca4c47dd669f97b95956d223485333d14\" alt=\"{\\displaystyle {\\begin{alignedat}{3}0&amp;:=&amp;&amp;\\quad \\ \\,\\{\\}&amp;&amp;=\\emptyset \\\\1&amp;:=0'&amp;&amp;=\\{0\\}&amp;&amp;=\\{\\emptyset \\}\\\\2&amp;:=1'&amp;&amp;=\\{0,1\\}&amp;&amp;=\\{\\emptyset ,\\{\\emptyset \\}\\}\\\\3&amp;:=2'&amp;&amp;=\\{0,1,2\\}&amp;&amp;=\\{\\emptyset ,\\{\\emptyset \\},\\{\\emptyset ,\\{\\emptyset \\}\\}\\}\\\\&amp;\\vdots &amp;&amp;&amp;&amp;\\\\(n+1)&amp;:=n'&amp;&amp;=\\{0,1,\\ldots ,n\\}&amp;&amp;=n\\cup \\{n\\}\\end{alignedat}}}\" aria-hidden=\"true\" \/><!--more--><\/p>\n<p>Whole numbers are simply expanded <em>naturals<\/em> into the negative direction, a non-orthogonal mirror view on the same axis if you like. Rational numbers are defined as fractions of such <em>integers<\/em> which may be presented using decimal numbers where they may lose precision already, especially when applied in a computer program using <em>float<\/em>.<br \/>\nIts hard to cope with the loss of precision using floats for e.g. 1\/3, which error may even explode in non-linear <a href=\"https:\/\/en.wikipedia.org\/wiki\/Propagation_of_uncertainty\">propagation of uncertainty<\/a> when applied to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Numerical_error\">(exponential) computation<\/a>.<\/p>\n<p>As mentioned, computer floats have their additional lack of accuracy due to their lack of precision to either end. Here a little chart showing the <a href=\"https:\/\/de.wikipedia.org\/wiki\/Datei:Exakt_darstellbare_Gleitkommazahlen.png\">accurate representable floats according to their mantissa size<\/a> which very well visualizes their lack of linear representation or better, the many holes they leave behind. <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/8\/8f\/Exakt_darstellbare_Gleitkommazahlen.png\/800px-Exakt_darstellbare_Gleitkommazahlen.png\" srcset=\"\/\/upload.wikimedia.org\/wikipedia\/commons\/8\/8f\/Exakt_darstellbare_Gleitkommazahlen.png 1.5x\" alt=\"Datei:Exakt darstellbare Gleitkommazahlen.png\" width=\"800\" height=\"436\" data-file-width=\"1100\" data-file-height=\"600\" \/>These holes are manifested as so called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Round-off_error\">round-off errors<\/a> and potentially sum up and multiplied, distorting the final result.<\/p>\n<p>I picked up this material issue in our little <a href=\"https:\/\/jausoft.com\/cgit\/cs_class\/\">cs-class<\/a> with my older son while continuously rotating geometric objects, represented by integer numbers. In our first attempt, we just rounded up the rotation-float-expression. The object&#8217;s were continuously rotated and visibly distorted their shape more and more in the process. It was quite fun to watch. We created two solutions for this problem, just using floats or storing the angle for an otherwise axis-aligned shape. A third solution would have been to actually use fractions&#8230;<\/p>\n<p>This reminded me of the fixed <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/numeric\/ratio\">compile-time rational arithmetic<\/a> in C++, i.e. <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/numeric\/ratio\/ratio\">std::ratio<\/a> but also <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/chrono\/duration\">std::chrono::duration<\/a>. While I embrace the power of C++ application of <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/constexpr\"><em>constexpr<\/em><\/a> compile time functional expression, I also love to use them at runtime with numbers derived in a non literal constant fashion.<\/p>\n<p>Hence i indulged myself writing <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/classjau_1_1fraction.html#details\">jau::fraction&lt;T&gt;<\/a> to dive a little bit deeper into this space and also read about Euclid&#8217;s algorithm from <a href=\"https:\/\/www.claymath.org\/library\/historical\/euclid\/book07.html\">Euclid&#8217;s Elements ~300 BC, book VII<\/a>.<\/p>\n<p>Adding <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/namespacejau_1_1fractions__i64__literals.html\">literals<\/a> to these fractions renders the code frictionless using the <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Integer.html#ga9dbd6893207fb76d999f7af3fd1d9bc5\">greatest common divisor (gcd)<\/a> to calculate the <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Integer.html#gad1e541f94f16123af5794150991414e3\">least common multiple (lcm) with overflow checks<\/a> for addition and subtraction:<\/p>\n<pre>1000_ms == 1_s;\r\n60_s == 1_min;\r\nfraction_i64 a = 1000_ms, b = 1_s, c = a + b;\r\nfraction_i64 i = 1_s\/3_s, j = 4_d, k = i + j;<\/pre>\n<p>The above shows how to compare and compound fractions of a different base w\/o losing precision at runtime, spending two 64-bit integer values for the signed numerator and unsigned denominator.<\/p>\n<h3>Implemented Time in C++<\/h3>\n<p>I probably won&#8217;t live beyond year 2262, which is the limit when using a signed 64-bit nanosecond <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/chrono\/time_point\">std::chrono::time_point<\/a>. However, I may reach beyond year 2038, which is the ceiling by using a <a href=\"https:\/\/en.cppreference.com\/w\/c\/chrono\/timespec\">struct timespec<\/a> on 32-bit platforms having <em>tv_sec<\/em> only last for 68 years since 1970 Unix Epoch. Both limitations are of historical nature and I believe we should do better and foremost more accurate.<\/p>\n<p>Of course, we already have 64-bit variants of <em>struct timespec<\/em> designed and supported by underlying newer kernels\/OS. We still lack of proper user-land libc support on GNU\/Linux to my knowledge, including pthreads. Therefor it is best advised to utilize a 64-bit system. This is also true for embedded systems, especially since the modern architecture also provides a more <a href=\"https:\/\/www.cl.cam.ac.uk\/~pes20\/cpp\/cpp0xmappings.html\">efficient cash load and store implementation for atomic operations<\/a>. <a href=\"https:\/\/www.think-cell.com\/en\/career\/talks\/pdf\/think-cell_talk_memorymodel.pdf\">C++ memory-model slides<\/a> and SC-DRF <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/atomic\/memory_order\">std::memory_order<\/a> might be of interest.<\/p>\n<p>To provide at least a timeless notion of a time point storage type today, I introduced <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html#details\">jau::fraction_timespec<\/a>. This new type is simply an enforced 64-bit signed <em>struct timespec<\/em> with the capability to convert from and to fractions and supporting all customary <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">time retrieval<\/a>, <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga511a6f414bc6826d316ed91a29e64694\">sleep<\/a> and pthreads-based <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga564eec6adf9c60517aeda9a5b8c120a3\">wait_until()<\/a> and <a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga23c343c839cbda11ae70470557de75e5\">wait_for()<\/a> functions.<\/p>\n<pre><a class=\"el\" title=\"Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html\">    fraction_timespec<\/a> t0 = <a class=\"el\" title=\"Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">getMonotonicTime()<\/a>;\r\n    \/\/ do something\r\n\r\n    \/\/ Exact duration\r\n<a class=\"el\" title=\"Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html\">    fraction_timespec<\/a> td_1 = <a class=\"el\" title=\"Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">getMonotonicTime()<\/a> - t0;\r\n\r\n    \/\/ or for durations &lt;= 292 years\r\n    fraction_i64 td_2 = (<a class=\"el\" title=\"Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">getMonotonicTime()<\/a> - t0).<a class=\"el\" title=\"Returns the sum of both components.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html#a5cd07a712340f97b6567d68ce96f8361\">to_fraction_i64()<\/a>;\r\n    sleep_for( td_2 + 1_ms ); \/\/ sleep for measured period + 1 ms\r\n\r\n    \/\/ same sleep as above, but expressed in absolute time\r\n<a class=\"el\" title=\"Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html\">    fraction_timespec<\/a> absolute_time = <a class=\"el\" title=\"Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">getMonotonicTime()<\/a> + td_2;\r\n<a href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#gad327e6df39e9df8009876414d7609161\">    sleep_until<\/a>( absolute_time + 1_ms ); \r\n<\/pre>\n<p>And here the fine details of wait for a condition variable in time limited fashion. When using a condition predicate loop to ensure no spurious wake-up preemptively ends waiting for the condition variable event or timeout, it is always recommended to use <a class=\"el\" title=\"wait_until causes the current thread to block until the condition variable is notified,...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga564eec6adf9c60517aeda9a5b8c120a3\">wait_until()<\/a> using the absolute timeout time computed once before said loop. Example from <a class=\"el\" title=\"Blocks the calling thread until the internal counter reaches 0 or the given timeout duration has expi...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/classjau_1_1latch.html#a7173f0d2301b0c4ec3ece1c960b68909\">latch::wait_for()<\/a>:<\/p>\n<pre>     std::unique_lock&lt;std::mutex&gt; lock(mtx_cd);\r\n     const <a class=\"el\" title=\"Timespec structure using int64_t for its components in analogy to struct timespec_t on 64-bit platfor...\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/structjau_1_1fraction__timespec.html\">fraction_timespec<\/a> timeout_time = <a class=\"el\" title=\"Returns current monotonic time since Unix Epoch 00:00:00 UTC on 1970-01-01.\" href=\"https:\/\/jausoft.com\/projects\/jaulib\/build\/documentation\/cpp\/html\/group__Fractions.html#ga9e7260d4bc825f09c92cf9ff9b1166a9\">getMonotonicTime()<\/a> + timeout_duration;\r\n     while( 0 &lt; count ) {\r\n         std::cv_status s = wait_until(cv, lock, timeout_time);\r\n         if( 0 == count ) {\r\n             return true;\r\n         }\r\n         if( std::cv_status::timeout == s ) {\r\n             return false;\r\n         }\r\n     }\r\n<\/pre>\n<p>Note that the implemented time functions may operate on monotonic or wall-clock time, as supported by the underlying <a href=\"https:\/\/www.gnu.org\/software\/libc\/manual\/html_node\/Waiting-with-Explicit-Clocks.html\"><em>pthread_cond_clockwait()<\/em><\/a> if available and user-library kernel <em><a href=\"https:\/\/man7.org\/linux\/man-pages\/man2\/clock_nanosleep.2.html\">clock_nanosleep()<\/a>, <\/em>both still using the aforementioned <em>struct timeval<\/em> &#8211; only timeless on 64-bit platforms.<\/p>\n<p>All of the above is now used in <a href=\"https:\/\/jausoft.com\/cgit\/direct_bt.git\/about\/\">Direct-BT<\/a>.<\/p>\n<p>&#8230; and this ends my little dive into fraction and times for today \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Natural numbers are defined as the sequence of numbers fully defined by their initial value, its successor and the successor of its successor and so forth. Despite the beauty of their intrinsic Dedekind\u2013Peano axioms, they are also fully proven by induction.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[59,3,50,58],"tags":[51,52,13,63,33,60,62,61],"class_list":["post-1049","post","type-post","status-publish","format-standard","hentry","category-c-language","category-computer-stuff","category-direct_bt","category-computer-languages","tag-c","tag-direct-bt","tag-embedded-device","tag-fractions","tag-linux","tag-memory-model","tag-precision","tag-time"],"_links":{"self":[{"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/posts\/1049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/comments?post=1049"}],"version-history":[{"count":15,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/posts\/1049\/revisions"}],"predecessor-version":[{"id":1064,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/posts\/1049\/revisions\/1064"}],"wp:attachment":[{"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/media?parent=1049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/categories?post=1049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jausoft.com\/blog\/wp-json\/wp\/v2\/tags?post=1049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}