<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title></title>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css">
<style type="text/css"><!--
body {
  margin: 5px 5px 5px 5px;
  background-color: #ffffff;
}
/* ========== Text Styles ========== */
hr { color: #000000}
body, table /* Normal text */
{
 font-size: 9pt;
 font-family: 'Courier New';
 font-style: normal;
 font-weight: normal;
 color: #000000;
 text-decoration: none;
}
span.rvts1 /* Heading */
{
 font-size: 10pt;
 font-family: 'Arial';
 font-weight: bold;
 color: #0000ff;
}
span.rvts2 /* Subheading */
{
 font-size: 10pt;
 font-family: 'Arial';
 font-weight: bold;
 color: #000080;
}
span.rvts3 /* Keywords */
{
 font-size: 10pt;
 font-family: 'Arial';
 font-style: italic;
 color: #800000;
}
a.rvts4, span.rvts4 /* Jump 1 */
{
 font-size: 10pt;
 font-family: 'Arial';
 color: #008000;
 text-decoration: underline;
}
a.rvts5, span.rvts5 /* Jump 2 */
{
 font-size: 10pt;
 font-family: 'Arial';
 color: #008000;
 text-decoration: underline;
}
span.rvts6
{
 font-size: 11pt;
 font-family: 'tahoma';
 font-weight: bold;
 color: #ffffff;
}
span.rvts7
{
 font-family: 'tahoma';
}
span.rvts8
{
 font-size: 11pt;
 font-family: 'tahoma';
}
a.rvts9, span.rvts9
{
 font-family: 'tahoma';
 color: #0000ff;
 text-decoration: underline;
}
span.rvts10
{
 font-size: 8pt;
 font-family: 'arial';
 font-style: italic;
 color: #c0c0c0;
}
/* ========== Para Styles ========== */
p,ul,ol /* Paragraph Style */
{
 text-align: left;
 text-indent: 0px;
 padding: 0px 0px 0px 0px;
 margin: 0px 0px 0px 0px;
}
.rvps1 /* Centered */
{
 text-align: center;
}
--></style>
</head>
<body>

<p><br></p>
<p>There is a reliable way to compute the exact number of floating-point "intervals" (one less than the number of FP numbers) between any two FP numbers. It is a long-ago solved problem. I have attached a C++ version. You can't define closeness by a "distance" in a FP system - you should use this measure instead (called "ulps" - units in the last place). The distance between large FP numbers may always be greater than the tolerance you prescribe. The spacing between adjacent FP numbers at the top of the scale for IEEE double precision numbers is 2^(972) (approx. 10^(293))! I doubt you're gping to make your tolerance this big. I don't believe newbies can grasp this, but they can be taught to get a "feel" for floating-point number systems. You can't write reliable FP code without this understanding. See http://uvsc.freshsources.com/decimals.pdf.</p>
<p><br></p>
<p>Sunday, February 12, 2006, 11:44:51 AM, you wrote:</p>
<p><br></p>
<div><table border=0 cellpadding=1 cellspacing=2 style="border-color: #000000; border-style: solid; background-color: #ffffff;">
<tr valign=top>
<td width=14 style="background-color: #0000ff;">
<p><span class=rvts6>&gt;</span></p>
</td>
<td width=711>
<p><span class=rvts7>I've been thinking about a function that was recently proposed at python-dev named 'areclose'. It is a function that is meant to tell whether two (or possible more) numbers are close to each other. It is a function similar to one that exists in Numeric. One such implementation is</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>def areclose(x,y,abs_tol=1e-8,rel_tol=1e-5):</span></p>
<p><span class=rvts7>&nbsp; &nbsp; diff = abs(x-y)</span></p>
<p><span class=rvts7>&nbsp; &nbsp; return diff &lt;= ans_tol or diff &lt;= rel_tol*max(abs(x),abs(y))</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>(This is the form given by Scott Daniels on python-dev.)</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Anyway, one of the rationales for including such a function was:&nbsp;</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>When teaching some programming to total newbies, a common frustration</span></p>
<p><span class=rvts7>is how to explain why a==b is False when a and b are floats computed</span></p>
<p><span class=rvts7>by different routes which ``should'' give the same results (if</span></p>
<p><span class=rvts7>arithmetic had infinite precision). &nbsp;Decimals can help, but another</span></p>
<p><span class=rvts7>approach I've found useful is embodied in Numeric.allclose(a,b) --</span></p>
<p><span class=rvts7>which returns True if all items of the arrays are ``close'' (equal to</span></p>
<p><span class=rvts7>within certain absolute and relative tolerances)</span></p>
<p><span class=rvts7>The problem with the above function, however, is that it *itself* has a comparison between floats and it will give undesired result for something like the following test:</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts7>&gt;&gt;&gt; print areclose(2, 2.1, .1, 0) #see if 2 and 2.1 are within 0.1 of each other</span></p>
<p><span class=rvts7>False</span></p>
<p><span class=rvts7>&gt;&gt;&gt;</span></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Here is an alternative that might be a nice companion to the repr() and round() functions: nice(). It is a combination of Tim Peter's delightful 'case closed' presentation in the thread, "Rounding to n significant digits?" [1] and the hidden magic of "prints" simplification of floating point numbers when being asked to show them.&nbsp;</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>It's default behavior is to return a number in the form that the number would have when being printed. An optional argument, however, allows the user to specify the number of digits to round the number to as counted from the most significant digit. (An alternative name, then, could be 'lround' but I think there is less baggage for the new user to think about if the name is something like nice()--a function that makes the floating point numbers "play nice." And I also think the name...sounds nice.)&nbsp;</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Here it is in action:</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts7>&gt;&gt;&gt; 3*1.1==3.3</span></p>
<p><span class=rvts7>False</span></p>
<p><span class=rvts7>&gt;&gt;&gt; nice(3*1.1)==nice(3.3)</span></p>
<p><span class=rvts7>True</span></p>
<p><span class=rvts7>&gt;&gt;&gt; x=3.21/0.65; print x</span></p>
<p><span class=rvts7>4.93846153846</span></p>
<p><span class=rvts7>&gt;&gt;&gt; print nice(x,2)</span></p>
<p><span class=rvts7>4.9</span></p>
<p><span class=rvts7>&gt;&gt;&gt; x=x*1e5; print nice(x,2)</span></p>
<p><span class=rvts7>490000.0</span></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Here's the function:&nbsp;</span></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts7>def nice(x,leadingDigits=0):</span></p>
<p><span class=rvts7>&nbsp;"""Return x either as 'print' would show it (the default) or rounded to the</span></p>
<p><span class=rvts7>&nbsp;specified digit as counted from the leftmost non-zero digit of the number,</span></p>
<p><span class=rvts7>&nbsp;</span></p>
<p><span class=rvts7>&nbsp;e.g. nice(0.00326,2) --&gt; 0.0033"""</span></p>
<p><span class=rvts7>&nbsp;assert leadingDigits&gt;=0</span></p>
<p><span class=rvts7>&nbsp;if leadingDigits==0:</span></p>
<p><span class=rvts7>&nbsp; return float(str(x)) #just give it back like 'print' would give it</span></p>
<p><span class=rvts7>&nbsp;leadingDigits=int(leadingDigits)</span></p>
<p><span class=rvts7>&nbsp;return float('%.*e' % (leadingDigits,x)) #give it back as rounded by the %e format</span></p>
<p><br></p>
<p><span class=rvts7>###</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Might something like this be useful? For new users, no arguments are needed other than x and floating points suddenly seem to behave in tests made using nice() values. It's also useful for those computing who want to show a physically meaningful value that has been rounded to the appropriate digit as counted from the most significant digit rather than from the decimal point.&nbsp;</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>Some time back I had worked on the significant digit problem and had several math calls to figure out what the exponent was. The beauty of Tim's solution is that you just use built in string formatting to do the work. Nice.</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>/c</span></p>
<p><span class=rvts8>&nbsp;</span></p>
<p><span class=rvts7>[1]&nbsp;</span><a class=rvts9 href="http://mail.python.org/pipermail/tutor/2004-July/030324.html">http://mail.python.org/pipermail/tutor/2004-July/030324.html</a></p>
</td>
</tr>
</table>
</div>
<p><br></p>
<p><br></p>
<p><br></p>
<p><br></p>
<p><span class=rvts10>--&nbsp;</span></p>
<p><span class=rvts10>Best regards,</span></p>
<p><span class=rvts10>&nbsp;Chuck</span></p>

</body></html>