Boost C++ Libraries: Ticket #12327: cpp_rational::convert_to<double>() does not return the nearest number https://svn.boost.org/trac10/ticket/12327 <p> Hello, </p> <p> I tested with the following program to see if boost::multiprecision::cpp_rational::convert_to&lt;double&gt;() returns the nearest double number to the exact value. I expected it to print only "true"s, but it actually prints some "false"s too. Is it a bug or (un)documented behavior? </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/multiprecision/cpp_int.hpp&gt;</span><span class="cp"></span> <span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">multiprecision</span><span class="o">::</span><span class="n">cpp_rational</span> <span class="n">NT</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">test_convert_to_double</span><span class="p">(</span><span class="kt">double</span> <span class="n">d1</span><span class="p">,</span> <span class="kt">double</span> <span class="n">d2</span><span class="p">)</span> <span class="p">{</span> <span class="n">NT</span> <span class="n">r1</span><span class="p">(</span><span class="n">d1</span><span class="p">);</span> <span class="n">NT</span> <span class="n">r2</span><span class="p">(</span><span class="n">d2</span><span class="p">);</span> <span class="n">NT</span> <span class="n">two</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="n">NT</span> <span class="n">three</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span> <span class="n">NT</span> <span class="n">r112</span> <span class="o">=</span> <span class="p">(</span><span class="n">two</span> <span class="o">*</span> <span class="n">r1</span> <span class="o">+</span> <span class="n">r2</span><span class="p">)</span> <span class="o">/</span> <span class="n">three</span><span class="p">;</span> <span class="n">NT</span> <span class="n">r12</span> <span class="o">=</span> <span class="p">(</span><span class="n">r1</span> <span class="o">+</span> <span class="n">r2</span><span class="p">)</span> <span class="o">/</span> <span class="n">two</span><span class="p">;</span> <span class="n">NT</span> <span class="n">r122</span> <span class="o">=</span> <span class="p">(</span><span class="n">r1</span> <span class="o">+</span> <span class="n">two</span> <span class="o">*</span> <span class="n">r2</span><span class="p">)</span> <span class="o">/</span> <span class="n">three</span><span class="p">;</span> <span class="kt">double</span> <span class="n">rd1</span> <span class="o">=</span> <span class="n">r1</span><span class="p">.</span><span class="n">convert_to</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span> <span class="kt">double</span> <span class="n">rd112</span> <span class="o">=</span> <span class="n">r112</span><span class="p">.</span><span class="n">convert_to</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span> <span class="kt">double</span> <span class="n">rd12</span> <span class="o">=</span> <span class="n">r12</span><span class="p">.</span><span class="n">convert_to</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span> <span class="kt">double</span> <span class="n">rd122</span> <span class="o">=</span> <span class="n">r122</span><span class="p">.</span><span class="n">convert_to</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span> <span class="kt">double</span> <span class="n">rd2</span> <span class="o">=</span> <span class="n">r2</span><span class="p">.</span><span class="n">convert_to</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;</span><span class="p">();</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">boolalpha</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">rd1</span> <span class="o">==</span> <span class="n">d1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">rd112</span> <span class="o">==</span> <span class="n">d1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">rd12</span> <span class="o">==</span> <span class="n">d2</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">rd122</span> <span class="o">==</span> <span class="n">d2</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">rd2</span> <span class="o">==</span> <span class="n">d2</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="k">volatile</span> <span class="kt">double</span> <span class="n">a</span> <span class="o">=</span> <span class="mf">0.099999999999999992</span><span class="p">;</span> <span class="k">volatile</span> <span class="kt">double</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">0.10000000000000001</span><span class="p">;</span> <span class="k">volatile</span> <span class="kt">double</span> <span class="n">c</span> <span class="o">=</span> <span class="mf">0.10000000000000002</span><span class="p">;</span> <span class="c1">// prints true, false, true, true, true</span> <span class="n">test_convert_to_double</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span> <span class="c1">// prints true, true, false, false, true</span> <span class="n">test_convert_to_double</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div><p> I compiled this program with MSVC 14.0 and ICL 16.0.3, both for x64 Debug build. They give the same results. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12327 Trac 1.4.3 John Maddock Thu, 14 Jul 2016 17:00:01 GMT <link>https://svn.boost.org/trac10/ticket/12327#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12327#comment:1</guid> <description> <p> I believe it's an error in your test program, taking the first example: </p> <pre class="wiki">0.099999999999999992 = 7205759403792793/72057594037927936 0.10000000000000001 = 3602879701896397/36028797018963968 </pre><p> Note that these fractions are exact (in the binary, not decimal sense). </p> <p> Then <a class="changeset" href="https://svn.boost.org/trac10/changeset/112" title="Fix link to test site. ">r112</a> becomes 5404319552844595/54043195528445952 which is 0.0999999999999999962992565845828115319212277730305989583... in decimal, which rounds up to 0.10000000000000001 and not down to 0.099999999999999992 due to the "6" after the string of 9's. </p> </description> <category>Ticket</category> </item> <item> <author>komakisen@…</author> <pubDate>Fri, 15 Jul 2016 04:46:21 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/12327#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12327#comment:2</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/12327#comment:1" title="Comment 1">johnmaddock</a>: </p> <blockquote class="citation"> <p> Then <a class="changeset" href="https://svn.boost.org/trac10/changeset/112" title="Fix link to test site. ">r112</a> becomes 5404319552844595/54043195528445952 which is 0.0999999999999999962992565845828115319212277730305989583... in decimal, which rounds up to 0.10000000000000001 and not down to 0.099999999999999992 due to the "6" after the string of 9's. </p> </blockquote> <p> Thank you for investigating my program, but I still don't understand this point. </p> <p> To begin with, 0.099999999999999992 is actually 0.09999999999999999167332... and 0.10000000000000001 is actually 0.1000000000000000055511... (they differ by 1ulp) </p> <p> So 0.09999999999999999629925... is less than their midpoint 0.09999999999999999861222... </p> <p> Also, <code>double</code> is a binary floating-point number. Thus I believe round-off calculation on a decimal digit "6" explains nothing here. </p> <p> If I run the following program, I get 0.099999999999999992. </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;iomanip&gt;</span><span class="cp"></span> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="kt">double</span> <span class="n">d</span> <span class="o">=</span> <span class="mf">0.09999999999999999629926</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">setprecision</span><span class="p">(</span><span class="mi">17</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">d</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div><p> So isn't 0.099999999999999992 the expected result? Or am I confusing myself? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>John Maddock</dc:creator> <pubDate>Mon, 25 Jul 2016 18:17:56 GMT</pubDate> <title>status, milestone changed; resolution set https://svn.boost.org/trac10/ticket/12327#comment:3 https://svn.boost.org/trac10/ticket/12327#comment:3 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">To Be Determined</span> → <span class="trac-field-new">Boost 1.62.0</span> </li> </ul> <p> You're correct, I was the one confused! </p> <p> Fixed in <a class="ext-link" href="https://github.com/boostorg/multiprecision/commit/7ebd9dfd9b0bc463642b065036a3cd6947a74431"><span class="icon">​</span>https://github.com/boostorg/multiprecision/commit/7ebd9dfd9b0bc463642b065036a3cd6947a74431</a>. </p> <p> However, your second test case still fails testing rd12, in this case I *think* the bug is yours: <a class="changeset" href="https://svn.boost.org/trac10/changeset/12" title="More things getting included from common. ">r12</a> is </p> <p> <code>14411518807585589/144115188075855872</code> </p> <blockquote> <p> which in binary is exactly the 54 bit quantity: </p> </blockquote> <pre class="wiki">0.000 1100110011 0011001100 1100110011 0011001100 1100110011 010 1 rounded here ^ </pre><p> And in this case no rounding up occurs since we have a tie and round to even. </p> <p> Please do correct me and re-open if I'm wrong! :) </p> Ticket komakisen@… Tue, 26 Jul 2016 14:41:34 GMT <link>https://svn.boost.org/trac10/ticket/12327#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12327#comment:4</guid> <description> <p> Great work! Thank you very much! :) </p> <blockquote class="citation"> <p> And in this case no rounding up occurs since we have a tie and round to even. </p> </blockquote> <p> Yes, you're right! Sorry for messing up. </p> </description> <category>Ticket</category> </item> </channel> </rss>