奇怪的情况下四舍五入到最接近的0.05 - 特殊情况

时间:2017-08-16 22:33:02

标签: python rounding precision

为了舍入到最接近的0.05,我只是将其除以0.05然后乘以0.05。如其他类似问题所述。

In [119]: (127.651//0.05)*0.05
Out[119]: 127.65

In [120]: (127.6501//0.05)*0.05
Out[120]: 127.65

In [121]: (127.65000001//0.05)*0.05
Out[121]: 127.65

In [122]: (127.65000000001//0.05)*0.05
Out[122]: 127.65

In [123]: (127.6500000000001//0.05)*0.05
Out[123]: 127.65

直到这里按预期行事。 但是对于这种特殊情况:

In [124]: (127.650000000000000001//0.05)*0.05
Out[124]: 127.60000000000001

我原本预计会有127.65。

在分手之前尝试四舍五入,但又一次......奇怪。 不仅我得到意想不到的结果(期望127.65),而且它给出超过2位小数的结果,这将导致我的进一步处理功能失败。

In [125]: (round(127.650000000000000001,5)//0.05)*0.05
Out[125]: 127.60000000000001

如果我只执行内轮,o / p是127.65 ......

In [126]: round(127.650000000000000001,5)
Out[126]: 127.65

但是在添加除法和乘法逻辑时......结果会出乎意料。

In [125]: (round(127.650000000000000001,5)//0.05)*0.05
Out[125]: 127.60000000000001

是否存在任何数据类型问题?或python的内部精度限制?

我如何以优雅的方式克服它?

PS:

1)我正在使用python 2.7

2)我最终在一个函数中使用它。这个特殊情况给出了意想不到的结果。我无法控制输入数据质量及其数据精度,因为它来自将csv文件读取到数据帧。

def RP(price):# Round down to the nearest price quotable ...i.e. multiple of 0.05
        return(round(price//0.05*0.05,2))

1 个答案:

答案 0 :(得分:0)

最后is-floating-point-math-broken中提到的扩展逻辑对我有用。

In [200]: (int(127.65*100)//5*5)/100.0
Out[200]: 127.65

In [201]:

In [201]: (int(127.65000000000000001*100)//5*5)/100.0
Out[201]: 127.65

或:

In [286]: int(127.65*20)/20.0
Out[286]: 127.65

In [287]: int(127.6500000000000000000000001*20)/20.0
Out[287]: 127.65

<强>更新

对于我的预期目的,(四舍五入到最接近的0.05以获得报价),到目前为止,这是我在搜索和检查多个值和迭代结果这么多天后可以找到的最接近的解决方案。

def RP(price):# Round to the nearest price quotable ...i.e. multiple of 0.05
        return(round(price*20.0,0)/20.0)

def RP_down(price):# Round_Down to the price quotable ...i.e. multiple of 0.05
        return(int(price*20.0)/20.0)

def RP_up(price):# Round_UP to the price quotable ...i.e. multiple of 0.05
        return(0.05 + int(price*20.0)/20.0)

为什么会这样?以下解释如下:

乘以20.0后跟round()或int(),将域从浮点数更改为整数。

因此,消除了导致意外结果的精度问题。

注意:在最后一步(除以20.0),我们再次从整数移动到浮点,但是具有正确的预期值(从过去的生产中运行到目前为止没有惊喜)周)。并且你知道它确实理论上它只有2个小数位(整数除以20),所以如果需要,你可以在你的程序的其余部分通过在打印时切掉其余部分来处理它。