Why does the floating-point value of 4*0.1 look nice in Python 3 but 3*0.1 doesn't?
<p>I know that most decimals don't have an exact floating point representation (<a href="http://stackoverflow.com/questions/588004">Is floating point math broken?</a>).</p>

<p>But I don't see why <code>4*0.1</code> is printed nicely as <code>0.4</code>, but <code>3*0.1</code> isn't, when
both values actually have ugly decimal representations:</p>

<pre><code>&gt;&gt;&gt; 3*0.1
0.30000000000000004
&gt;&gt;&gt; 4*0.1
0.4
&gt;&gt;&gt; from decimal import Decimal
&gt;&gt;&gt; Decimal(3*0.1)
Decimal('0.3000000000000000444089209850062616169452667236328125')
&gt;&gt;&gt; Decimal(4*0.1)
Decimal('0.40000000000000002220446049250313080847263336181640625')
</code></pre>

<p>The simple answer is because <code>3*0.1 != 0.3</code> due to quantization (roundoff) error (whereas <code>4*0.1 == 0.4</code> because multiplying by a power of two is usually an "exact" operation).</p>

<p>You can use the <code>.hex</code> method in Python to view the internal representation of a number (basically, the <em>exact</em> binary floating point value, rather than the base-10 approximation). This can help to explain what's going on under the hood.</p>

<pre><code>&gt;&gt;&gt; (0.1).hex()
'0x1.999999999999ap-4'
&gt;&gt;&gt; (0.3).hex()
'0x1.3333333333333p-2'
&gt;&gt;&gt; (0.1*3).hex()
'0x1.3333333333334p-2'
&gt;&gt;&gt; (0.4).hex()
'0x1.999999999999ap-2'
&gt;&gt;&gt; (0.1*4).hex()
'0x1.999999999999ap-2'
</code></pre>

<p>0.1 is 0x1.999999999999a times 2^-4. The "a" at the end means the digit 10 - in other words, 0.1 in binary floating point is <em>very slightly</em> larger than the "exact" value of 0.1 (because the final 0x0.99 is rounded up to 0x0.a). When you multiply this by 4, a power of two, the exponent shifts up (from 2^-4 to 2^-2) but the number is otherwise unchanged, so <code>4*0.1 == 0.4</code>.</p>

<p>However, when you multiply by 3, the little tiny difference between 0x0.99 and 0x0.a0 (0x0.07) magnifies into a 0x0.15 error, which shows up as a one-digit error in the last position. This causes 0.1*3 to be <em>very slightly</em> larger than the rounded value of 0.3.</p>

<p>Python 3's float <code>repr</code> is designed to be <em>round-trippable</em>, that is, the value shown should be exactly convertible into the original value. Therefore, it cannot display <code>0.3</code> and <code>0.1*3</code> exactly the same way, or the two <em>different</em> numbers would end up the same after round-tripping. Consequently, Python 3's <code>repr</code> engine chooses to display one with a slight apparent error.</p>

python floating-point rounding floating-accuracy ieee-754