题主测试的和那个bug无关。round是四舍六入五成双的。
python 的官方实现确实有问题,至于为什么作者不改进,原作者可能是什么心态,可以参见刘海洋的答案。大致心态也许是:反正这个错误不在我,所以虽然有方法,但我也不会去解决这个问题。
Python 的 round 问题是个典型的例子,推测作者的观点是认为这类与浮点数精确度有关的问题没有解决的必要。如同 @刘海洋 的观点一样,所以导致了现在的结果。
不过仔细分析会发现,0.5 这种浮点数是可以被精确表示的,而 round 这个函数的特定性在于,round 舍入之后的精确性毫无意义。所以 round 这个问题本身造成的不精确性是可以被解决的。
对于 round 的不精确性,重要的在于结果是进一还是去尾。我写了一个简单的例子来说明这个问题,当然这个函数在特定情况下也不准确,不过在题目给出的情况下都可以得到正确的结果。
<code class="language-c"><span class="cp">#include <stdio.h></stdio.h></span>
<span class="kt">float</span> <span class="nf">my_round</span><span class="p">(</span><span class="kt">float</span> <span class="n">src</span><span class="p">,</span> <span class="kt">int</span> <span class="n">idx</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="n">idx</span><span class="p">;</span><span class="n">i</span><span class="o">--</span><span class="p">;)</span>
<span class="n">src</span> <span class="o">*=</span><span class="mi">10</span><span class="p">;</span>
<span class="kt">float</span> <span class="n">dest</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">src</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">src</span> <span class="o">>=</span> <span class="n">dest</span><span class="o">+</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">dest</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="n">idx</span><span class="p">;</span><span class="n">i</span><span class="o">--</span><span class="p">;)</span>
<span class="n">dest</span> <span class="o">/=</span><span class="mi">10</span><span class="p">;</span>
<span class="k">return</span> <span class="n">dest</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">1.5</span><span class="p">,</span> <span class="mi">0</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">1.25</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">1.245</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">1.45</span><span class="p">,</span> <span class="mi">1</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">1.415</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"result=%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">my_round</span><span class="p">(</span><span class="mf">2.675</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>
<span class="p">}</span>
</code>
两个问题,一个是
浮点数在计算机中的真实存储(这里是在 Python 中的存储)
<code class="language-text">expect: 1.0
actual: 1
expect: 1.1
actual: 1.100000000000000088817841970012523233890533447265625
expect: 1.2
actual: 1.1999999999999999555910790149937383830547332763671875
expect: 1.3
actual: 1.3000000000000000444089209850062616169452667236328125
expect: 1.4
actual: 1.399999999999999911182158029987476766109466552734375
expect: 1.5
actual: 1.5
expect: 1.6
actual: 1.600000000000000088817841970012523233890533447265625
expect: 1.7
actual: 1.6999999999999999555910790149937383830547332763671875
expect: 1.8
actual: 1.8000000000000000444089209850062616169452667236328125
expect: 1.9
actual: 1.899999999999999911182158029987476766109466552734375
</code>
很简单,因为2.675在表示的时候可能是2.6749,所以round以后还是2.67了
你的需求本质是:精确小数运算。然而,float不是为了满足这一需求而设计的,decimal才是。所以,为float单独定制一个round,不符合float的设计意图,也很难实现。以你的函数为例,temp*10这个操作在float下不是精确的。
>>> 1.222*10
12.219999999999999
我的意思是为啥不写个可以解决这个问题的函数:例如(仅仅一个例子,可能从性能啊之类肯定不行,官方是出于什么原因不写一个类似的)
def myround(par,l):
temp = 1
for i in range(l):
temp*=10
v = int((par+0.5/temp)*temp) / temp
return v
i = 1.25
print(myround(i,1))
i = 1.245
print(myround(i,2))
i = 1.21
print(myround(i,1))
i = 1.249
print(myround(i,2))
----
1.3
1.25
1.2
1.25
他的解释应该说的是这个不是个bug。默认数值都是float,float本来就不精确,所以python应该是只对decimal精确。我觉得这个也挺正常的。