72e469da0a
[CI SKIP]
416 lines
44 KiB
HTML
416 lines
44 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
|
<title>Floating-point Comparison</title>
|
|
<link rel="stylesheet" href="../math.css" type="text/css">
|
|
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
|
<link rel="home" href="../index.html" title="Math Toolkit 2.11.0">
|
|
<link rel="up" href="../utils.html" title="Chapter 2. Floating Point Utilities">
|
|
<link rel="prev" href="next_float/ulp.html" title="Obtaining the Size of a Unit In the Last Place - ULP">
|
|
<link rel="next" href="cond.html" title="Condition Numbers">
|
|
</head>
|
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
<table cellpadding="2" width="100%"><tr>
|
|
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
|
|
<td align="center"><a href="../../../../../index.html">Home</a></td>
|
|
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
|
|
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
|
|
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
|
|
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
|
|
</tr></table>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="next_float/ulp.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../utils.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="cond.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
|
|
</div>
|
|
<div class="section">
|
|
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
|
<a name="math_toolkit.float_comparison"></a><a class="link" href="float_comparison.html" title="Floating-point Comparison">Floating-point Comparison</a>
|
|
</h2></div></div></div>
|
|
<p>
|
|
Comparison of floating-point values has always been a source of endless difficulty
|
|
and confusion.
|
|
</p>
|
|
<p>
|
|
Unlike integral values that are exact, all floating-point operations will potentially
|
|
produce an inexact result that will be rounded to the nearest available binary
|
|
representation. Even apparently inocuous operations such as assigning 0.1 to
|
|
a double produces an inexact result (as this decimal number has no exact binary
|
|
representation).
|
|
</p>
|
|
<p>
|
|
Floating-point computations also involve rounding so that some 'computational
|
|
noise' is added, and hence results are also not exact (although repeatable,
|
|
at least under identical platforms and compile options).
|
|
</p>
|
|
<p>
|
|
Sadly, this conflicts with the expectation of most users, as many articles
|
|
and innumerable cries for help show all too well.
|
|
</p>
|
|
<p>
|
|
Some background reading is:
|
|
</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem">
|
|
Knuth D.E. The art of computer programming, vol II, section 4.2, especially
|
|
Floating-Point Comparison 4.2.2, pages 198-220.
|
|
</li>
|
|
<li class="listitem">
|
|
<a href="http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html" target="_top">David
|
|
Goldberg, "What Every Computer Scientist Should Know About Floating-Point
|
|
Arithmetic"</a>
|
|
</li>
|
|
<li class="listitem">
|
|
<a href="http://adtmag.com/articles/2000/03/16/comparing-floatshow-to-determine-if-floating-quantities-are-close-enough-once-a-tolerance-has-been-r.aspx" target="_top">Alberto
|
|
Squassabia, Comparing floats listing</a>
|
|
</li>
|
|
<li class="listitem">
|
|
<a href="https://code.google.com/p/googletest/wiki/AdvancedGuide#Floating-Point_Comparison" target="_top">Google
|
|
Floating-Point_Comparison guide</a>
|
|
</li>
|
|
<li class="listitem">
|
|
<a href="https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/testing_tools/extended_comparison/floating_point.html" target="_top">Boost.Test
|
|
Floating-Point_Comparison</a>
|
|
</li>
|
|
</ul></div>
|
|
<p>
|
|
Boost provides a number of ways to compare floating-point values to see if
|
|
they are tolerably close enough to each other, but first we must decide what
|
|
kind of comparison we require:
|
|
</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem">
|
|
Absolute difference/error: the absolute difference between two values
|
|
<span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span> is simply <code class="computeroutput"><span class="identifier">fabs</span><span class="special">(</span><span class="identifier">a</span><span class="special">-</span><span class="identifier">b</span><span class="special">)</span></code>. This is the only meaningful comparison
|
|
to make if we know that the result may have cancellation error (see below).
|
|
</li>
|
|
<li class="listitem">
|
|
The edit distance between the two values: i.e. how many (binary) floating-point
|
|
values are between two values <span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span>?
|
|
This is provided by the function <a href="../../../../../libs/math/doc/html/math_toolkit/next_float/float_distance.html" target="_top">Boost.Math
|
|
float_distance</a>, but is probably only useful when you know that
|
|
the distance should be very small. This function is somewhat difficult
|
|
to compute, and doesn't scale to values that are very far apart. In other
|
|
words, use with care.
|
|
</li>
|
|
<li class="listitem">
|
|
The relative distance/error between two values. This is quick and easy
|
|
to compute, and is generally the method of choice when checking that your
|
|
results are "tolerably close" to one another. However, it is
|
|
not as exact as the edit distance when dealing with small differences,
|
|
and due to the way floating-point values are encoded can "wobble"
|
|
by a factor of 2 compared to the "true" edit distance. This is
|
|
the method documented below: if <code class="computeroutput"><span class="identifier">float_distance</span></code>
|
|
is a surgeon's scalpel, then <code class="computeroutput"><span class="identifier">relative_difference</span></code>
|
|
is more like a Swiss army knife: both have important but different use
|
|
cases.
|
|
</li>
|
|
</ul></div>
|
|
<h6>
|
|
<a name="math_toolkit.float_comparison.h0"></a>
|
|
<span class="phrase"><a name="math_toolkit.float_comparison.fp_relative"></a></span><a class="link" href="float_comparison.html#math_toolkit.float_comparison.fp_relative">Relative
|
|
Comparison of Floating-point Values</a>
|
|
</h6>
|
|
<p>
|
|
<code class="computeroutput"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">special_functions</span><span class="special">/</span><span class="identifier">relative_difference</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span></code>
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">U</span><span class="special">></span>
|
|
<a class="link" href="result_type.html" title="Calculation of the Type of the Result"><span class="emphasis"><em>calculated-result-type</em></span></a> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">U</span> <span class="identifier">b</span><span class="special">);</span>
|
|
|
|
<span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">U</span><span class="special">></span>
|
|
<a class="link" href="result_type.html" title="Calculation of the Type of the Result"><span class="emphasis"><em>calculated-result-type</em></span></a> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">U</span> <span class="identifier">b</span><span class="special">);</span>
|
|
</pre>
|
|
<p>
|
|
The function <code class="computeroutput"><span class="identifier">relative_difference</span></code>
|
|
returns the relative distance/error <span class="emphasis"><em>E</em></span> between two values
|
|
as defined by:
|
|
</p>
|
|
<div class="blockquote"><blockquote class="blockquote"><p>
|
|
<span class="serif_italic">E = fabs((a - b) / min(a,b))</span>
|
|
</p></blockquote></div>
|
|
<p>
|
|
The function <code class="computeroutput"><span class="identifier">epsilon_difference</span></code>
|
|
is a convenience function that returns <code class="computeroutput"><span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span>
|
|
<span class="identifier">b</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">eps</span></code> where
|
|
<code class="computeroutput"><span class="identifier">eps</span></code> is the machine epsilon
|
|
for the result type.
|
|
</p>
|
|
<p>
|
|
The following special cases are handled as follows:
|
|
</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem">
|
|
If either of <span class="emphasis"><em>a</em></span> or <span class="emphasis"><em>b</em></span> is a NaN,
|
|
then returns the largest representable value for T: for example for type
|
|
<code class="computeroutput"><span class="keyword">double</span></code>, this is <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">double</span><span class="special">>::</span><span class="identifier">max</span><span class="special">()</span></code>
|
|
which is the same as <code class="computeroutput"><span class="identifier">DBL_MAX</span></code>
|
|
or <code class="computeroutput"><span class="number">1.7976931348623157e+308</span></code>.
|
|
</li>
|
|
<li class="listitem">
|
|
If <span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span> differ in sign then
|
|
returns the largest representable value for T.
|
|
</li>
|
|
<li class="listitem">
|
|
If both <span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span> are both infinities
|
|
(of the same sign), then returns zero.
|
|
</li>
|
|
<li class="listitem">
|
|
If just one of <span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span> is an
|
|
infinity, then returns the largest representable value for T.
|
|
</li>
|
|
<li class="listitem">
|
|
If both <span class="emphasis"><em>a</em></span> and <span class="emphasis"><em>b</em></span> are zero then
|
|
returns zero.
|
|
</li>
|
|
<li class="listitem">
|
|
If just one of <span class="emphasis"><em>a</em></span> or <span class="emphasis"><em>b</em></span> is a zero
|
|
or a denormalized value, then it is treated as if it were the smallest
|
|
(non-denormalized) value representable in T for the purposes of the above
|
|
calculation.
|
|
</li>
|
|
</ul></div>
|
|
<p>
|
|
These rules were primarily designed to assist with our own test suite, they
|
|
are designed to be robust enough that the function can in most cases be used
|
|
blindly, including in cases where the expected result is actually too small
|
|
to represent in type T and underflows to zero.
|
|
</p>
|
|
<h6>
|
|
<a name="math_toolkit.float_comparison.h1"></a>
|
|
<span class="phrase"><a name="math_toolkit.float_comparison.examples"></a></span><a class="link" href="float_comparison.html#math_toolkit.float_comparison.examples">Examples</a>
|
|
</h6>
|
|
<p>
|
|
Some using statements will ensure that the functions we need are accessible.
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
or
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">relative_difference</span><span class="special">;</span>
|
|
<span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">epsilon_difference</span><span class="special">;</span>
|
|
<span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">float_next</span><span class="special">;</span>
|
|
<span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">float_prior</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
The following examples display values with all possibly significant digits.
|
|
Newer compilers should provide <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="identifier">FPT</span><span class="special">>::</span><span class="identifier">max_digits10</span></code> for this purpose, and here we
|
|
use <code class="computeroutput"><span class="keyword">float</span></code> precision where <code class="computeroutput"><span class="identifier">max_digits10</span></code> = 9 to avoid displaying a distracting
|
|
number of decimal digits.
|
|
</p>
|
|
<div class="note"><table border="0" summary="Note">
|
|
<tr>
|
|
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
|
|
<th align="left">Note</th>
|
|
</tr>
|
|
<tr><td align="left" valign="top"><p>
|
|
Older compilers can use this formula to calculate <code class="computeroutput"><span class="identifier">max_digits10</span></code>
|
|
from <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="identifier">FPT</span><span class="special">>::</span><span class="identifier">digits10</span></code>:    <code class="computeroutput"><span class="keyword">int</span>
|
|
<span class="identifier">max_digits10</span> <span class="special">=</span>
|
|
<span class="number">2</span> <span class="special">+</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="identifier">FPT</span><span class="special">>::</span><span class="identifier">digits10</span>
|
|
<span class="special">*</span> <span class="number">3010</span><span class="special">/</span><span class="number">10000</span><span class="special">;</span></code>
|
|
</p></td></tr>
|
|
</table></div>
|
|
<p>
|
|
One can set the display including all trailing zeros (helpful for this example
|
|
to show all potentially significant digits), and also to display <code class="computeroutput"><span class="keyword">bool</span></code> values as words rather than integers:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">.</span><span class="identifier">precision</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">max_digits10</span><span class="special">);</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">boolalpha</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">showpoint</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
When comparing values that are <span class="emphasis"><em>quite close</em></span> or <span class="emphasis"><em>approximately
|
|
equal</em></span>, we could use either <code class="computeroutput"><span class="identifier">float_distance</span></code>
|
|
or <code class="computeroutput"><span class="identifier">relative_difference</span></code>/<code class="computeroutput"><span class="identifier">epsilon_difference</span></code>, for example with type
|
|
<code class="computeroutput"><span class="keyword">float</span></code>, these two values are adjacent
|
|
to each other:
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">float</span> <span class="identifier">a</span> <span class="special">=</span> <span class="number">1</span><span class="special">;</span>
|
|
<span class="keyword">float</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">1</span> <span class="special">+</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">epsilon</span><span class="special">();</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"a = "</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"b = "</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"float_distance = "</span> <span class="special"><<</span> <span class="identifier">float_distance</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
Which produces the output:
|
|
</p>
|
|
<pre class="programlisting">a = 1.00000000
|
|
b = 1.00000012
|
|
float_distance = 1.00000000
|
|
relative_difference = 1.19209290e-007
|
|
epsilon_difference = 1.00000000
|
|
</pre>
|
|
<p>
|
|
In the example above, it just so happens that the edit distance as measured
|
|
by <code class="computeroutput"><span class="identifier">float_distance</span></code>, and the
|
|
difference measured in units of epsilon were equal. However, due to the way
|
|
floating point values are represented, that is not always the case:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">a</span> <span class="special">=</span> <span class="number">2.0f</span> <span class="special">/</span> <span class="number">3.0f</span><span class="special">;</span> <span class="comment">// 2/3 inexactly represented as a float</span>
|
|
<span class="identifier">b</span> <span class="special">=</span> <span class="identifier">float_next</span><span class="special">(</span><span class="identifier">float_next</span><span class="special">(</span><span class="identifier">float_next</span><span class="special">(</span><span class="identifier">a</span><span class="special">)));</span> <span class="comment">// 3 floating point values above a</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"a = "</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"b = "</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"float_distance = "</span> <span class="special"><<</span> <span class="identifier">float_distance</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
Which produces the output:
|
|
</p>
|
|
<pre class="programlisting">a = 0.666666687
|
|
b = 0.666666865
|
|
float_distance = 3.00000000
|
|
relative_difference = 2.68220901e-007
|
|
epsilon_difference = 2.25000000
|
|
</pre>
|
|
<p>
|
|
There is another important difference between <code class="computeroutput"><span class="identifier">float_distance</span></code>
|
|
and the <code class="computeroutput"><span class="identifier">relative_difference</span><span class="special">/</span><span class="identifier">epsilon_difference</span></code>
|
|
functions in that <code class="computeroutput"><span class="identifier">float_distance</span></code>
|
|
returns a signed result that reflects which argument is larger in magnitude,
|
|
where as <code class="computeroutput"><span class="identifier">relative_difference</span><span class="special">/</span><span class="identifier">epsilon_difference</span></code>
|
|
simply return an unsigned value that represents how far apart the values are.
|
|
For example if we swap the order of the arguments:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"float_distance = "</span> <span class="special"><<</span> <span class="identifier">float_distance</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="identifier">a</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="identifier">a</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span> <span class="identifier">a</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
The output is now:
|
|
</p>
|
|
<pre class="programlisting">float_distance = -3.00000000
|
|
relative_difference = 2.68220901e-007
|
|
epsilon_difference = 2.25000000
|
|
</pre>
|
|
<p>
|
|
Zeros are always treated as equal, as are infinities as long as they have the
|
|
same sign:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">a</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
|
|
<span class="identifier">b</span> <span class="special">=</span> <span class="special">-</span><span class="number">0</span><span class="special">;</span> <span class="comment">// signed zero</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">a</span> <span class="special">=</span> <span class="identifier">b</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">infinity</span><span class="special">();</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="special">-</span><span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
Which produces the output:
|
|
</p>
|
|
<pre class="programlisting">relative_difference = 0.000000000
|
|
relative_difference = 0.000000000
|
|
relative_difference = 3.40282347e+038
|
|
</pre>
|
|
<p>
|
|
Note that finite values are always infinitely far away from infinities even
|
|
if those finite values are very large:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">a</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">max</span><span class="special">)();</span>
|
|
<span class="identifier">b</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">infinity</span><span class="special">();</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"a = "</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"b = "</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
Which produces the output:
|
|
</p>
|
|
<pre class="programlisting">a = 3.40282347e+038
|
|
b = 1.#INF0000
|
|
relative_difference = 3.40282347e+038
|
|
epsilon_difference = 3.40282347e+038
|
|
</pre>
|
|
<p>
|
|
Finally, all denormalized values and zeros are treated as being effectively
|
|
equal:
|
|
</p>
|
|
<pre class="programlisting"><span class="identifier">a</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">float</span><span class="special">>::</span><span class="identifier">denorm_min</span><span class="special">();</span>
|
|
<span class="identifier">b</span> <span class="special">=</span> <span class="identifier">a</span> <span class="special">*</span> <span class="number">2</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"a = "</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"b = "</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"float_distance = "</span> <span class="special"><<</span> <span class="identifier">float_distance</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">a</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"a = "</span> <span class="special"><<</span> <span class="identifier">a</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"b = "</span> <span class="special"><<</span> <span class="identifier">b</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"float_distance = "</span> <span class="special"><<</span> <span class="identifier">float_distance</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"relative_difference = "</span> <span class="special"><<</span> <span class="identifier">relative_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"epsilon_difference = "</span> <span class="special"><<</span> <span class="identifier">epsilon_difference</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
</pre>
|
|
<p>
|
|
Which produces the output:
|
|
</p>
|
|
<pre class="programlisting">a = 1.40129846e-045
|
|
b = 2.80259693e-045
|
|
float_distance = 1.00000000
|
|
relative_difference = 0.000000000
|
|
epsilon_difference = 0.000000000
|
|
a = 0.000000000
|
|
b = 2.80259693e-045
|
|
float_distance = 2.00000000
|
|
relative_difference = 0.000000000
|
|
epsilon_difference = 0.000000000</pre>
|
|
<p>
|
|
Notice how, in the above example, two denormalized values that are a factor
|
|
of 2 apart are none the less only one representation apart!
|
|
</p>
|
|
<p>
|
|
All the above examples are contained in <a href="../../../example/float_comparison_example.cpp" target="_top">float_comparison_example.cpp</a>.
|
|
</p>
|
|
<h6>
|
|
<a name="math_toolkit.float_comparison.h2"></a>
|
|
<span class="phrase"><a name="math_toolkit.float_comparison.small"></a></span><a class="link" href="float_comparison.html#math_toolkit.float_comparison.small">Handling
|
|
Absolute Errors</a>
|
|
</h6>
|
|
<p>
|
|
Imagine we're testing the following function:
|
|
</p>
|
|
<pre class="programlisting"><span class="keyword">double</span> <span class="identifier">myspecial</span><span class="special">(</span><span class="keyword">double</span> <span class="identifier">x</span><span class="special">)</span>
|
|
<span class="special">{</span>
|
|
<span class="keyword">return</span> <span class="identifier">sin</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="special">-</span> <span class="identifier">sin</span><span class="special">(</span><span class="number">4</span> <span class="special">*</span> <span class="identifier">x</span><span class="special">);</span>
|
|
<span class="special">}</span>
|
|
</pre>
|
|
<p>
|
|
This function has multiple roots, some of which are quite predicable in that
|
|
both <code class="computeroutput"><span class="identifier">sin</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span></code> and <code class="computeroutput"><span class="identifier">sin</span><span class="special">(</span><span class="number">4</span><span class="identifier">x</span><span class="special">)</span></code> are zero
|
|
together. Others occur because the values returned from those two functions
|
|
precisely cancel out. At such points the relative difference between the true
|
|
value of the function and the actual value returned may be <span class="emphasis"><em>arbitrarily
|
|
large</em></span> due to <a href="http://en.wikipedia.org/wiki/Loss_of_significance" target="_top">cancellation
|
|
error</a>.
|
|
</p>
|
|
<p>
|
|
In such a case, testing the function above by requiring that the values returned
|
|
by <code class="computeroutput"><span class="identifier">relative_error</span></code> or <code class="computeroutput"><span class="identifier">epsilon_error</span></code> are below some threshold is
|
|
pointless: the best we can do is to verify that the <span class="emphasis"><em>absolute difference</em></span>
|
|
between the true and calculated values is below some threshold.
|
|
</p>
|
|
<p>
|
|
Of course, determining what that threshold should be is often tricky, but a
|
|
good starting point would be machine epsilon multiplied by the largest of the
|
|
values being summed. In the example above, the largest value returned by <code class="computeroutput"><span class="identifier">sin</span><span class="special">(</span><span class="identifier">whatever</span><span class="special">)</span></code> is 1, so simply using machine epsilon as the
|
|
target for maximum absolute difference might be a good start (though in practice
|
|
we may need a slightly higher value - some trial and error will be necessary).
|
|
</p>
|
|
</div>
|
|
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
|
<td align="left"></td>
|
|
<td align="right"><div class="copyright-footer">Copyright © 2006-2019 Nikhar
|
|
Agrawal, Anton Bikineev, Paul A. Bristow, Marco Guazzone, Christopher Kormanyos,
|
|
Hubert Holin, Bruno Lalande, John Maddock, Jeremy Murphy, Matthew Pulver, Johan
|
|
Råde, Gautam Sewani, Benjamin Sobotta, Nicholas Thompson, Thijs van den Berg,
|
|
Daryle Walker and Xiaogang Zhang<p>
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
|
|
</p>
|
|
</div></td>
|
|
</tr></table>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="next_float/ulp.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../utils.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="cond.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
|
|
</div>
|
|
</body>
|
|
</html>
|