Determine how many decimal digits of a float are precise
<p>In my real-life problem, I multiply the size of a widget, with a <code>size_hint</code> which can be anything from <code>0.</code> to <code>1.</code>. Assuming the minimum size of a widget is <code>0</code> and the max size is <code>10,000</code>, on which digit should I expect the error to occur, when I multiply <code>size * size_hint</code>? </p>

<p>For example* on <code>0.1</code> the error occurs on the.. </p>

<pre><code>&gt;&gt;&gt; from decimal import Decimal
&gt;&gt;&gt; Decimal.from_float(.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
#                           ^ 
#                           |_ here 
</code></pre>

<p>.. 18th decimal digit.</p>

<p>On the other hand, the error below occurs on the 14th decimal </p>

<pre><code>&gt;&gt;&gt; 1001*.2
200.20000000000002
</code></pre>

<p><strong>Questions</strong>:   </p>

<ul>
<li>Is there a way to determine on which exactly decimal digit the error will occur? </li>
<li>Is there a difference between Python 2 and Python 3?</li>
</ul>

<p>Using decimals instead of floats is not a option, and that both <code>size</code> and <code>size_hint</code> are provided by the user.</p>

<hr>

<p>*<sub>  I used <a href="https://docs.python.org/3.5/library/fractions.html" rel="nofollow"><code>Fraction</code></a> since <code>&gt;&gt;&gt; 0.1</code> is displayed as.. <code>0.1</code> in the console, but I think this is related to how it's printed, not how it's stored. </sub></p>

<p>If we assume that the size of the widget is stored exactly, then there are 2 sources of error: the conversion of <code>size_hint</code> from decimal -> binary, and the multiplication. In Python, these should both be correctly rounded to nearest, so each should have relative error of half an ulp (<a href="https://en.wikipedia.org/wiki/Unit_in_the_last_place" rel="nofollow">unit in the last place</a>). Since the second operation is a multiplication we can just add the bounds to get a total relative error which will be bounded 1 ulp, or 2<sup>-53</sup>.</p>

<p>Converting to decimal:</p>

<pre><code>&gt;&gt;&gt; math.trunc(math.log10(2.0**-53))
-15
</code></pre>

<p>this means you should be accurate to 15 significant figures.</p>

<p>There shouldn't be any difference between Python 2 and 3: Python has long been fairly strict about floating point behaviour, the only change I'm aware of is the behaviour of the <code>round</code> function, which isn't used here.</p>

python floating-point precision significant-digits