Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>(Edited) Rounding integers with floating point is the easiest solution to this problem; however, depending on the problem set is may be possible. For example, in embedded systems the floating point solution may be too costly.</p> <p>Doing this using integer math turns out to be kind of hard and a little unintuitive. The first posted solution worked okay for the the problem I had used it for but after characterizing the results over the range of integers it turned out to be very bad in general. Looking through several books on bit twiddling and embedded math return few results. A couple of notes. First, I only tested for positive integers, my work does not involve negative numerators or denominators. Second, and exhaustive test of 32 bit integers is computational prohibitive so I started with 8 bit integers and then mades sure that I got similar results with 16 bit integers.</p> <p>I started with the 2 solutions that I had previously proposed:</p> <p><code>#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)</code></p> <p><code>#define DIVIDE_WITH_ROUND(N, D) (N == 0) ? 0:(N - D/2)/D + 1;</code></p> <p>My thought was that the first version would overflow with big numbers and the second underflow with small numbers. I did not take 2 things into consideration. 1.) the 2nd problem is actually recursive since to get the correct answer you have to properly round D/2. 2.) In the first case you often overflow and then underflow, the two canceling each other out. Here is an error plot of the two (incorrect) algorithms:<img src="https://i.stack.imgur.com/sWhmn.png" alt="Divide with Round1 8 bit x=numerator y=denominator"></p> <p>This plot shows that the first algorithm is only incorrect for small denominators (0 &lt; d &lt; 10). Unexpectedly it actually handles <em>large</em> numerators better than the 2nd version.</p> <p>Here is a plot of the 2nd algorithm: <img src="https://i.stack.imgur.com/Ry1Dl.png" alt="8 bit signed numbers 2nd algorithm."></p> <p>As expected it fails for small numerators but also fails for more large numerators than the 1st version.</p> <p>Clearly this is the better starting point for a correct version:</p> <p><code>#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)</code></p> <p>If your denominators is > 10 then this will work correctly.</p> <p>A special case is needed for D == 1, simply return N. A special case is needed for D== 2, = N/2 + (N &amp; 1) // Round up if odd.</p> <p>D >= 3 also has problems once N gets big enough. It turns out that larger denominators only have problems with larger numerators. For 8 bit signed number the problem points are</p> <p><code>if (D == 3) &amp;&amp; (N &gt; 75))<br> else if ((D == 4) &amp;&amp; (N &gt; 100))<br> else if ((D == 5) &amp;&amp; (N &gt; 125))<br> else if ((D == 6) &amp;&amp; (N &gt; 150))<br> else if ((D == 7) &amp;&amp; (N &gt; 175))<br> else if ((D == 8) &amp;&amp; (N &gt; 200))<br> else if ((D == 9) &amp;&amp; (N &gt; 225))<br> else if ((D == 10) &amp;&amp; (N &gt; 250))</code> </p> <p>(return D/N for these)</p> <p>So in general the the pointe where a particular numerator gets bad is somewhere around<br> <code>N &gt; (MAX_INT - 5) * D/10</code> </p> <p>This is not exact but close. When working with 16 bit or bigger numbers the error &lt; 1% if you just do a C divide (truncation) for these cases.</p> <p>For 16 bit signed numbers the tests would be</p> <p><code>if ((D == 3) &amp;&amp; (N &gt;= 9829))<br> else if ((D == 4) &amp;&amp; (N &gt;= 13106))<br> else if ((D == 5) &amp;&amp; (N &gt;= 16382))<br> else if ((D == 6) &amp;&amp; (N &gt;= 19658))<br> else if ((D == 7) &amp;&amp; (N &gt;= 22935))<br> else if ((D == 8) &amp;&amp; (N &gt;= 26211))<br> else if ((D == 9) &amp;&amp; (N &gt;= 29487))<br> else if ((D == 10) &amp;&amp; (N &gt;= 32763))</code></p> <p>Of course for unsigned integers MAX_INT would be replaced with MAX_UINT. I am sure there is an exact formula for determining the largest N that will work for a particular D and number of bits but I don't have any more time to work on this problem...</p> <p>(I seem to be missing this graph at the moment, I will edit and add later.) This is a graph of the 8 bit version with the special cases noted above:![8 bit signed with special cases for <code>0 &lt; N &lt;= 10</code> <a href="https://i.stack.imgur.com/nXH1b.png" rel="noreferrer">3</a></p> <p>Note that for 8 bit the error is 10% or less for all errors in the graph, 16 bit is &lt; 0.1%. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload