mirror of
https://github.com/boostorg/test.git
synced 2026-01-26 19:12:10 +00:00
227 lines
9.9 KiB
HTML
227 lines
9.9 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<title>Floating point comparison</title>
|
|
<script language="javascript">var viso_path="js-lib"</script>
|
|
<script language="javascript" src="js-lib/core.js" > </script>
|
|
|
|
<script language="JavaScript">
|
|
JS.include( "btl.js" );
|
|
</script>
|
|
|
|
<script>put_screen_style();</script>
|
|
<link rel="stylesheet" type="text/css" href="style/btl_print.css" media="print" />
|
|
|
|
<meta http-equiv="Content-Language" content="en-us" />
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
</head>
|
|
|
|
<body onload="btl_menu_init()">
|
|
<div align="center">
|
|
<table class="body-table" cellspacing="3" >
|
|
<tr>
|
|
<td id="body">
|
|
|
|
<script language="Javascript">btl_header()</script>
|
|
|
|
<h1>Floating-point comparison algorithms</h1>
|
|
|
|
<p class="page-toc">
|
|
<a href="#Introduction">Introduction</a><br>
|
|
<a href="#tolerance">How to choose a tolerance</a><br>
|
|
<a href="#Specification">The close_at_tolerance algorithm</a><br>
|
|
<a href="#Compilation">Compilation</a><br>
|
|
<a href="#Acknowledgements">Acknowledgements</a><br>
|
|
<a href="#References">References</a>
|
|
</p>
|
|
|
|
<h2><a name="Introduction">Introduction</a></h2>
|
|
|
|
<p class="1-line-indented">In most cases it is unreasonable to use an operator=(...) for a
|
|
floating-point values equality check The simple solution like abs(f1-f2) <= e does not work
|
|
for very small or very big values. This floating-point comparison algorithm is
|
|
based on the more confident solution presented by Knuth in [1]. For a
|
|
given floating point values <i>u</i> and <i>v</i> and a tolerance <i>e</i>:</p>
|
|
|
|
<table class="2fields">
|
|
<tr>
|
|
<td>
|
|
<p style="text-indent: -20">
|
|
|<i> u </i>-<i> v </i>| <= <i>e * |u|</i> and |<i> u </i>-<i> v </i>| <= <i>e * |v|<br>
|
|
</i>defines a "very close with tolerance <i>e</i>" relationship between <i>u</i> and <i>v</i>
|
|
</td>
|
|
<td valign="top">
|
|
(<b><a name="F.1">1</a></b>)</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<p style="text-indent: -20">
|
|
|<i> u </i>-<i> v </i>| <= <i>e * |u|</i> or |<i> u </i>-<i> v </i>| <= <i>e * |v|<br>
|
|
</i>defines a "close enough with tolerance <i>e</i>" relationship between <i>u</i> and <i>v</i>
|
|
</td>
|
|
<td valign="top">
|
|
(<a name="F.1"><b>2</b></a>)
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p class="1-line-indented">Both relationships are commutative but are not transitive. The relationship
|
|
defined by inequations (<b>1</b>) is stronger that the relationship defined by
|
|
inequations (<b>2</b>) (i.e. (<b>1</b>) => (<b>2</b>) ). Because of the multiplication
|
|
in the right side of inequations, that could cause an unwanted underflow condition, the
|
|
implementation is using modified version of the inequations (<b>1</b>) and (<b>2</b>)
|
|
where all underflow, overflow conditions could be guarded safely:</p>
|
|
|
|
<table class="2fields">
|
|
<tr>
|
|
<td>
|
|
<p style="margin-left: -20">
|
|
|
|
|<i> u </i>-<i> v </i>| / <i> |u| </i><= <i>e</i> and |<i> u </i>-<i> v </i>| / <i> |v| </i><= <i>e<br>
|
|
</i>|<i> u </i>-<i> v </i>| / <i> |u| </i> <= <i>e</i> or |<i> u </i>-<i> v </i>| / <i> |v| </i> <= <i>e</i>
|
|
</td>
|
|
<td>
|
|
(<b>1`</b>)<br>
|
|
(<b>2`</b>)
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<script language="Javascript">put_ref_to_top()</script>
|
|
|
|
<h2><a name="tolerance">How to choose a tolerance</a></h2>
|
|
|
|
<p class="1-line-indented">In case of absence of a domain specific requirements the value of tolerance could be chosen
|
|
as a sum of the predicted upper limits for
|
|
"relative rounding errors" of compared values. The "rounding" is the operation
|
|
by which a real value 'x' is represented in a floating-point format with 'p'
|
|
binary digits (bits) as the floating-point value 'X'. The "relative rounding
|
|
error" is the difference between the real and the floating point values in
|
|
relation to real value: |x-X|/|x|. The discrepancy between real and floating
|
|
point value may be caused by several reasons:</p>
|
|
|
|
<ul>
|
|
<li>Type promotion</li>
|
|
<li>Arithmetic operations</li>
|
|
<li>Conversion from a decimal presentation to a binary presentation</li>
|
|
<li>Non-arithmetic operation</li>
|
|
</ul>
|
|
|
|
<p class="1-line-indented">The first two operations proved to have a relative rounding error that does
|
|
not exceed 1/2 * "machine epsilon value" for the appropriate floating point type
|
|
(represented by std::numeric_limits<FPT>::epsilon()). conversion to binary
|
|
presentation, sadly, does not have such requirement. So we can't assume that
|
|
float 1.1 is close to real 1.1 with tolerance 1/2 * "machine epsilon value" for
|
|
float (though for 11./10 we can). Non arithmetic operations
|
|
either do not have a predicted upper limit relative rounding errors. Note that both
|
|
arithmetic and non arithmetic operations might also produce others
|
|
"non-rounding" errors, such
|
|
as underflow/overflow,
|
|
division-by-zero or 'operation errors'. </p>
|
|
|
|
<p class="1-line-indented">All theorems about the upper limit of a rounding error, including that of
|
|
1/2*epsilon, refers <u>only</u> to the 'rounding' operation, nothing more. This
|
|
means that the 'operation error', that is, the error incurred by the operation
|
|
itself, besides rounding, isn't considered. In order for numerical software to
|
|
be able to actually predict error bounds, the IEEE754 standard requires
|
|
arithmetic operations to be 'correctly or exactly rounded'. That is, it is
|
|
required that the internal computation of a given operation be such that the
|
|
floating point result is the <u>exact</u> result rounded to the number of
|
|
working bits. In other words, it is required that the computation used by the
|
|
operation itself doesn't introduce any additional errors. The IEEE754 standard
|
|
does not require same behavior from most non-arithmetic operation. The
|
|
underflow/overflow and division-by-zero errors may cause rounding errors with unpredictable
|
|
upper limits.</p>
|
|
|
|
<p class="1-line-indented">For a given number of rounding error (in a simple case it's just a
|
|
number of floating point constants and arithmetic involved) it is proposed to calculate a tolerance as follows:</p>
|
|
|
|
|
|
<table class="2fields">
|
|
<tr>
|
|
<td>
|
|
<i>n</i>*std::numeric_limits<T>::epsilon()/2</td>
|
|
<td>
|
|
(<b>3</b>)
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p>where n is number of floating-point rounding errors.</p>
|
|
|
|
<p class="1-line-indented">For more reading about floating-point comparison see references at the end.</p>
|
|
|
|
<h2>The <a name="Specification">close_at_tolerance</a> algorithm</h2>
|
|
|
|
<p>The <b>
|
|
<a name="Specification">close_at_tolerance</a></b> algorithm allows to check the
|
|
relationship defines by inequations (<b><a href="#F.1">1</a></b>) or (<b><a href="#F.2">2</a></b>).
|
|
It is implemented as binary predicate.</p>
|
|
|
|
<pre class="code"><span class="reserv-word">template</span><<span class="reserv-word">typename</span> FPT>
|
|
<span class="reserv-word">class</span> close_at_tolerance
|
|
{
|
|
<span class="reserv-word">public</span>:
|
|
close_at_tolerance( FPT tolerance, <span class="cpp-type">bool</span> strong_or_weak = <span class="reserv-word">true</span> );
|
|
close_at_tolerance( <span class="cpp-type">int</span> number_of_rounding_errors,
|
|
<span class="cpp-type">bool</span> strong_or_weak = <span class="reserv-word">true</span> );
|
|
|
|
<span class="cpp-type">bool</span> <span class="reserv-word">operator</span>()( FPT left, FPT right ) <span class="reserv-word">const</span>;
|
|
};
|
|
</pre>
|
|
|
|
<p class="1-line-indented">The first constructor allows to specify a tolerance value to compare against.
|
|
The first constructor allows to specify a number of rounding errors, in which
|
|
case a tolerance is computed using expression (<b><a href="#F.3">3</a></b>). The
|
|
strong_or_weak switch allows to which relationship is checked. The default
|
|
behavior is to check strong relationship defined by inequations (<b><a href="#F.1">1</a></b>).<script language="Javascript">put_ref_to_top()</script></p>
|
|
<h2><a name="Compilation">Compilation</a></h2>
|
|
<p class="1-line-indented">The <b>
|
|
<a name="Specification">close_at_tolerance</a></b> algorithm is implemented in
|
|
the header file
|
|
<a href="../../../boost/test/detail/floating_point_comparison.hpp">
|
|
detail/floating_point_comparison.hpp</a>. It is recommended to use test tools
|
|
wrappers located on <a href="../../../boost/test/test_tools.hpp">test_tools.hpp</a>.
|
|
Note that you still need to include
|
|
<a href="../../../boost/test/detail/floating_point_comparison.hpp">
|
|
detail/floating_point_comparison.hpp</a> yourself since it does not get included
|
|
automatically.</p>
|
|
<h2><a name="Acknowledgement">Acknowledgement</a></h2>
|
|
<p class="1-line-indented">Fernando Cacciola for very helpful discussion of floating point arithmetic in
|
|
the boost forum.</p>
|
|
<h2><a name="References">References</a></h2>
|
|
<p>[1] Knuth D.E. <i>The art of computer programming</i> (vol II)<b>.</b><br>
|
|
[2] David Goldberg
|
|
<a href="http://docs.sun.com/htmlcoll/coll.648.2/iso-8859-1/NUMCOMPGD/ncg_goldberg.html">
|
|
What Every Computer Scientist Should Know About Floating-Point Arithmetic</a>
|
|
<br>
|
|
[3] Kulisch U.
|
|
<a href="http://www.dagstuhl.de/DATA/Events/00/00162.proceedings/papers/p00.ps">
|
|
Rounding near zero</a>.<br>
|
|
[4] Philippe Langlois
|
|
<a href="ftp://ftp.inria.fr/INRIA/publication/publi-pdf/RR/RR-3967.pdf">From
|
|
Rounding Error Estimation to Automatic Correction with Automatic Differentiation</a><br>
|
|
[5] Lots of information on William Kahan
|
|
<a href="http://www.cs.berkeley.edu/~wkahan/">home page</a><br>
|
|
[4] Alberto Squassabia <a href="http://www.joopmag.com/html/from_pages/crarticle.asp?ID=396">Comparing
|
|
Floats: How To Determine if Floating Quantities Are Close Enough Once a
|
|
Tolerance Has Been Reached</a><b> </b>C++ Report March 2000.<br>
|
|
[5] Pete Becker The Journeyman's Shop: Trap Handlers, Sticky Bits, and
|
|
Floating-Point Comparisons C/C++ Users Journal December 2000.<script language="Javascript">put_ref_to_top()</script></p>
|
|
<hr>
|
|
<p>© <script language="Javascript">contact_addess()</script>
|
|
<script language="Javascript">get_copyright_date()</script>
|
|
</p>
|
|
|
|
<p>Revised
|
|
<!--webbot bot="Timestamp" S-Type="EDITED"
|
|
S-Format="%d %b %Y" startspan -->28 Jul 2002<!--webbot bot="Timestamp" endspan i-checksum="15002" -->
|
|
</p>
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</body>
|
|
</html>
|