Boost C++ Libraries: Ticket #8379: side_by_triangle foils scaled-epsilon for equality by comparing determinant against zero https://svn.boost.org/trac10/ticket/8379 <p> In boost/geometry/strategies/cartesian/side_by_triangle.hpp: </p> <div class="wiki-code"><div class="code"><pre><span class="cm">/* 88*/</span> <span class="n">promoted_type</span> <span class="k">const</span> <span class="n">s</span> <span class="cm">/* 89*/</span> <span class="o">=</span> <span class="n">geometry</span><span class="o">::</span><span class="n">detail</span><span class="o">::</span><span class="n">determinant</span><span class="o">&lt;</span><span class="n">promoted_type</span><span class="o">&gt;</span> <span class="cm">/* 90*/</span> <span class="p">(</span> <span class="cm">/* 91*/</span> <span class="n">dx</span><span class="p">,</span> <span class="n">dy</span><span class="p">,</span> <span class="cm">/* 92*/</span> <span class="n">dpx</span><span class="p">,</span> <span class="n">dpy</span> <span class="cm">/* 93*/</span> <span class="p">);</span> <span class="cm">/* 94*/</span> <span class="cm">/* 95*/</span> <span class="n">promoted_type</span> <span class="k">const</span> <span class="n">zero</span> <span class="o">=</span> <span class="n">promoted_type</span><span class="p">();</span> <span class="cm">/* 96*/</span> <span class="k">return</span> <span class="n">math</span><span class="o">::</span><span class="n">equals</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">zero</span><span class="p">)</span> <span class="o">?</span> <span class="mi">0</span> <span class="cm">/* 97*/</span> <span class="o">:</span> <span class="n">s</span> <span class="o">&gt;</span> <span class="n">zero</span> <span class="o">?</span> <span class="mi">1</span> <span class="cm">/* 98*/</span> <span class="o">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> </pre></div></div><p> The math::equals() interface implements, in boost/geometry/util/math.hpp, an equality comparison with an epsilon value—scaled by its arguments—when the common type is a floating-point type: </p> <div class="wiki-code"><div class="code"><pre><span class="cm">/* 52*/</span> <span class="k">static</span> <span class="kr">inline</span> <span class="kt">bool</span> <span class="nf">apply</span><span class="p">(</span><span class="n">Type</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="n">Type</span> <span class="k">const</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="cm">/* 53*/</span> <span class="p">{</span> <span class="cm">/* 54*/</span> <span class="k">if</span> <span class="p">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">)</span> <span class="cm">/* 55*/</span> <span class="p">{</span> <span class="cm">/* 56*/</span> <span class="k">return</span> <span class="nb">true</span><span class="p">;</span> <span class="cm">/* 57*/</span> <span class="p">}</span> <span class="cm">/* 58*/</span> <span class="cm">/* 59*/</span> <span class="c1">// See http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17,</span> <span class="cm">/* 60*/</span> <span class="c1">// FUTURE: replace by some boost tool or boost::test::close_at_tolerance</span> <span class="cm">/* 61*/</span> <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">abs</span><span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">b</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="n">Type</span><span class="o">&gt;::</span><span class="n">epsilon</span><span class="p">()</span> <span class="o">*</span> <span class="n">get_max</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">abs</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">abs</span><span class="p">(</span><span class="n">b</span><span class="p">),</span> <span class="mf">1.0</span><span class="p">);</span> </pre></div></div><p> The scaling performed by the math::equals() interface fails to reliably reflect the scale of the original inputs to the determinant calculation (dx, dy, dpx, dpy) through no fault of its own; it was not passed the appropriate information. </p> <p> In particular, </p> <div class="wiki-code"><div class="code"><pre><span class="n">fma</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="o">-</span><span class="p">(</span><span class="n">x</span> <span class="o">*</span> <span class="n">y</span><span class="p">));</span> <span class="cm">/* x*y - x*y */</span> </pre></div></div><p> is known to produce, on some platforms, the double value which is nearest to the round-off from (x * y). This round-off can legitimately be greater than DBL_EPSILON. </p> <p> The determinant calculation in boost/geometry/arithmetic/determinant.hpp: </p> <div class="wiki-code"><div class="code"><pre><span class="cm">/* 42*/</span> <span class="k">return</span> <span class="nf">rt</span><span class="p">(</span><span class="n">ux</span><span class="p">)</span> <span class="o">*</span> <span class="n">rt</span><span class="p">(</span><span class="n">vy</span><span class="p">)</span> <span class="o">-</span> <span class="n">rt</span><span class="p">(</span><span class="n">uy</span><span class="p">)</span> <span class="o">*</span> <span class="n">rt</span><span class="p">(</span><span class="n">vx</span><span class="p">);</span> </pre></div></div><p> is liable to hit similar behaviour. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/8379 Trac 1.4.3 awulkiew Tue, 24 Mar 2015 01:23:26 GMT status, milestone changed; resolution set https://svn.boost.org/trac10/ticket/8379#comment:1 https://svn.boost.org/trac10/ticket/8379#comment:1 <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.58.0</span> </li> </ul> <p> Thanks for the report! It took a while to address it, sorry about that. </p> <p> For floating-point numbers, the result is now compared according to the machine epsilon scaled by the greatest value passed into the <code>determinant()</code> formula. </p> <p> The results of the determinant are compared this way not only in side_by_triangle but also cartesian intersection strategy. </p> <p> For the details see: </p> <ul><li><a class="ext-link" href="https://github.com/boostorg/geometry/commit/b5887efd5e839e0e458bce207a34272cc3193a5c"><span class="icon">​</span>https://github.com/boostorg/geometry/commit/b5887efd5e839e0e458bce207a34272cc3193a5c</a> </li><li><a class="ext-link" href="https://github.com/boostorg/geometry/commit/f59f6ffaceb6cb36f0b07ae24f01d8790527985c"><span class="icon">​</span>https://github.com/boostorg/geometry/commit/f59f6ffaceb6cb36f0b07ae24f01d8790527985c</a> </li><li><a class="ext-link" href="https://github.com/boostorg/geometry/commit/dbeb823fcbd8ef5c30f8c2a7f25f3ac2300a0f27"><span class="icon">​</span>https://github.com/boostorg/geometry/commit/dbeb823fcbd8ef5c30f8c2a7f25f3ac2300a0f27</a> </li></ul><p> Any suggestions are welcome! </p> Ticket