Note that there are some explanatory texts on larger screens.

plurals
  1. POBug in glibc `div()` code?
    primarykey
    data
    text
    <p>As quoted in "<a href="https://stackoverflow.com/questions/319880/integer-division-rounding-with-negatives-in-c">Integer division rounding with negatives in C++</a>", in C before C99 (i.e. in C89) and in C++ before C++11 (i.e. in C++98 and C++03), for an integer division computation where either operand is negative the sign of the remainder (or equivalently, the rounding direction of the quotient) is <em>implementation-defined</em>.</p> <p>Then comes the standard function <a href="http://en.cppreference.com/w/cpp/numeric/math/div" rel="nofollow noreferrer"><code>std::div</code></a> which is specified to <em>truncate the quotient towards zero</em> (i.e. the remainder has the same sign as the dividend (numerator)) (see for example <a href="https://stackoverflow.com/a/11726016/688659">this answer to "what is purpose of div() library function?"</a>).</p> <p>Here is glibc's code for <code>div()</code> (<a href="http://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/div.c;h=44a30a7ea485a9eef38fb4ffe6aaebdc06468b3b;hb=HEAD" rel="nofollow noreferrer">source</a>) (also quoted in "<a href="https://stackoverflow.com/questions/6718217/is-div-function-useful-stdlib-h">Is div function useful (stdlib.h)?</a>"):</p> <p>(Note: <code>div_t</code> is defined as:</p> <pre><code>typedef struct { int quot; int rem; } div_t; </code></pre> <p>-- end note.)</p> <pre><code>/* Return the `div_t' representation of NUMER over DENOM. */ div_t div (numer, denom) int numer, denom; { div_t result; result.quot = numer / denom; result.rem = numer % denom; /* The ANSI standard says that |QUOT| &lt;= |NUMER / DENOM|, where NUMER / DENOM is to be computed in infinite precision. In other words, we should always truncate the quotient towards zero, never -infinity. Machine division and remainer may work either way when one or both of NUMER or DENOM is negative. If only one is negative and QUOT has been truncated towards -infinity, REM will have the same sign as DENOM and the opposite sign of NUMER; if both are negative and QUOT has been truncated towards -infinity, REM will be positive (will have the opposite sign of NUMER). These are considered `wrong'. If both are NUM and DENOM are positive, RESULT will always be positive. This all boils down to: if NUMER &gt;= 0, but REM &lt; 0, we got the wrong answer. In that case, to get the right answer, add 1 to QUOT and subtract DENOM from REM. */ if (numer &gt;= 0 &amp;&amp; result.rem &lt; 0) { ++result.quot; result.rem -= denom; } return result; } </code></pre> <p>As you can see there is a test after the big comment block, whose purpose is to "correct" the result if the built-in division truncates towards -infinity instead of towards zero.</p> <p>Now the question:</p> <p><strong><em>Isn't there a bug in that code?</em></strong></p> <p>Let's first consider the example call <code>div(42, -5)</code>. "In math" <strong>42/-5</strong> is exactly <strong>-8.4</strong>, so theoretically in C89 and C++03 <code>42 / -5</code> could yield either <code>-8</code> (truncated) or <code>-9</code> (floored) depending on the implementation. Reading the code:</p> <ul> <li>If <code>42 / -5</code> yields <code>-8</code> then <code>42 % -5</code> yields <code>2</code> (as <code>42 == -8 * -5 + 2</code>), so the test is <code>(42 &gt;= 0 &amp;&amp; 2 &lt; 0)</code> which is not true and the above function returns <code>-8</code> and <code>2</code>, as wanted;</li> <li>If <code>42 / -5</code> yields <code>-9</code> then <code>42 % -5</code> yields <code>-3</code> (as <code>42 == -9 * -5 + -3</code>), so the test is <code>(42 &gt;= 0 &amp;&amp; -3 &lt; 0)</code> which <em>is</em> true, so the above function returns the "corrected" <code>-9 + 1</code> and <code>-3 - -5</code>, i.e. <code>-8</code> and <code>2</code>, as wanted.</li> </ul> <p>But now let's consider the call <code>div(-42, 5)</code> (signs inverted):</p> <ul> <li>If <code>-42 / 5</code> yields <code>-8</code> then <code>-42 % 5</code> yields <code>-2</code> (as <code>-42 == -8 * 5 + -2</code>), so the test is <code>(-42 &gt;= 0 &amp;&amp; -2 &lt; 0)</code> which is not true and the above function returns <code>-8</code> and <code>-2</code>, as wanted;</li> <li>If <code>-42 / 5</code> yields <code>-9</code> then <code>-42 % 5</code> yields <code>3</code> (as <code>-42 == -9 * 5 + 3</code>), so the test is <code>(-42 &gt;= 0 &amp;&amp; 3 &lt; 0)</code> which... is <em>not</em> true! and the above function <strong>returns <code>-9</code> and <code>3</code> instead of <code>-8</code> and <code>-2</code></strong>!</li> </ul> <p>The comment in the code above first seems right when it says that the situation that needs a correction is when "REM has the opposite sign of NUMER", but then it makes the <em>huge simplification</em> "This all boils down to: if NUMER >= 0, but REM &lt; 0, we got the wrong answer", which seems wrong (incomplete) to me because <strong>it omits the case</strong> "if NUMER &lt; 0, but REM > 0" (<code>-42</code> and <code>3</code> in the previous example).</p> <p>I can hardly believe that such a bug would have remained unnoticed since 1992 or 1990 (apparently <a href="http://minilib-c.googlecode.com/svn-history/r2/trunk/stdlib/div.c" rel="nofollow noreferrer">someone tried to "fix" it</a> but it still seems incorrect because <code>div(-42, 5)</code> could return <code>-10</code> and <code>8</code>)... Arguably, most implementations have been truncating towards zero by default (and all are required to do so starting from C99 and C++11, so the issue is "moot" in the latest Standards <sup>1</sup>) so the bug wouldn't manifest on them, but still... Maybe I'm missing something here?</p> <p>Thank you for any insights.</p> <hr> <p><sup>1</sup> <em>(Edit)</em> As for "the issue is moot in C++11 and C99 (and newer)": accordingly, in these Standards the built-in division is required to truncate towards zero, so we never need to adjust the result, but doesn't that then mean that the present implementation is <em>more complex than needed</em> and <em>unnecessarily inefficient</em>? The "big comment" is obsolete and the <code>if</code> test useless, so shouldn't that part just be removed entirely?</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.
 

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