在将欧元兑换成欧元时,有时会错过一分钱

时间:2016-04-20 00:45:16

标签: python python-2.7 currency

我必须将欧元(字符串)翻译成欧元美分(int):
示例:

  • '12,1'=> 1210
  • '14,51'=> 1451

我使用这个python函数:

int(round(float(amount.replace(',', '.')), 2) * 100)

但是这个数额'1229,8 4 '的结果是:12298 3

更新

我使用Wim的解决方案,因为我在Python / Jinja和javascript中使用整数进行货币艺术化。另见Chepner的答案。

int(round(100 * float(amout.replace(',', '.')), 2))

我的问题由Me先生解答,他解释了上述结果。

3 个答案:

答案 0 :(得分:3)

文档说什么,以及一个简单的解释

我试了一下,并对此事感到惊讶。所以我转向documentation,其中有一点说明。

  

注意浮点数round()的行为可能会令人惊讶:for   例如,round(2.675,2)给出2.67而不是预期的2.68。这个   这不是一个错误:它是大多数小数部分的结果   不能完全表示为浮点数。

现在这意味着什么,大多数小数部分不能表示为浮点数。好了,文档跟进了一个很棒的link来解释这个,但是既然你可能没有来这里阅读一个讨厌的技术文档,那么让我总结一下发生了什么。

Python使用IEEE-754浮点标准来表示浮点数。该标准降低了速度的准确性。有些数字无法准确表示。例如,.1实际上表示为0.1000000000000000055511151231257827021181583404541015625。有趣的是,二进制中的.1实际上是一个无限重复的数字,就像1/3是一个无限重复的.333333。

根据引擎盖案例研究

现在谈谈你的具体案例。这是非常有趣的,这是我发现的。

首先让我们简化您尝试做的事情

>>> amount = '1229,84'
>>> int(round(float(amount.replace(',', '.')), 2) * 100)
>>> 122983

>>>int(1229.84 * 100)
>>> 122983

有时Python 1 无法100%准确显示二进制浮点数,出于同样的原因,我们无法将小数1/3显示为小数。发生这种情况时,Python会隐藏任何额外的数字。 .1实际上存储为-0.10000000000000009 2 ,但如果您将其键入控制台,Python会将其显示为.1。我们可以通过int(1.1) - 1.1 3 来查看这些额外的数字。我们可以将此int(myNum) - myNum公式应用于大多数浮点数,以查看其后面隐藏的额外数字。 4 。在您的情况下,我们将执行以下操作。

>>> int(1229.84) - 1229.84
-0.8399999999999181

1229.84实际上是1229.8399999999999181。继续。 5

>>> 1229.84, 2) * 100
122983.99999999999 #there's all of our hidden digits showing up.

现在进入最后一步。这是我们关注的部分。将其更改回整数。

>>> int(122983.99999999999)
122983

它向下而不是向上,但是,如果我们从未将它乘以100,那么我们最后还会有2个9,而Python会向上舍入。

>>> int(122983.9999999999999)
122984

???现在发生了什么。为什么Python将122983.99999999999舍入为122983.9999999999999,但它会向122983.9999999999999舍入?好吧,每当Python将浮点数转换为整数时,它就会向下舍入。但是,您必须记住,Python 122984.0最后加上两个99,与>>> 122983.9999999999999 122984.0 >>> a = 122983.9999999999999 >>> int(a) - a 0.0 相同。例如。

>>> 122983.99999999999
122983.99999999999
>>> a=122983.99999999999
>>> int(a) - a
-0.9999999999854481

并且最后没有两个额外的99。

122983.9999999999999

Python绝对将122984.0视为122983.99999999999而不是122983.99999999999。现在回到将122984转换为整数。因为我们创建了一个小于122984的小数部分,Python认为它是来自122983的单独数字,并且因为转换为整数总是导致Python向下舍入,我们得到{{1结果。

呼。这要经历很多,但我确实学到了很多东西,我希望你能做到。所有这一切的解决方案是使用decimal数字而不是浮点数,这会降低准确性的速度。

舍入怎么样?最初的问题也有一些四舍五入 - 它没用。见附录项 6

解决方案

a)最简单的解决方案是使用decimal module而不是浮点数。这是在任何财务或会计计划中做事的首选方式。

文档还提到了我总结的以下解决方案。

b)可以通过myFloat.hex()float.fromhex(myHex)

以十六进制形式表达和检索确切的值

c)也可以通过myFloat.as_integer_ratio()

检索确切的值作为分数

d)文档简要提到使用SciPy进行浮点算法,但是SO question提到SciPy的NumPy浮点数只不过是内置浮点类型的别名。 decimal module将是更好的解决方案。

附录

1 - 尽管我经常会提到Python的行为,但我所谈论的内容是IEEE-754浮点标准的一部分,这是主要编程语言使用的标准。他们的浮点数。

2 - int(1.1) - 1.1给了我-0.10000000000000009,但根据documentation .1真的是0.1000000000000000055511151231257827021181583404541015625

3 - 我们使用int(1.1) - 1.1代替int(.1) - .1,因为int(.1) - .1没有给我们隐藏的数字,但根据文档他们应该仍然在那里对于.1,因此我说int(someNum) -someNum大部分时间都有效,但不是所有时间。

4 - 当我们使用公式int(myNum) - myNum时,发生的事情是将数字转换为整数会使数字向下舍入,因此int(3.9)变为3,当我们从3减去3.9我们留下-.9。但是,由于某种原因,我不知道,当我们摆脱所有整数时,我们只剩下小数部分,Python决定向我们展示一切 - 整个尾数。

5 - 这并不会真正影响我们的分析结果,但是当乘以100而不是隐藏的数字被移位2个小数位时,它们也会改变一点。 / p>

    >>> a = 1229.84
    >>> int(a) - a
    -0.8399999999999181
    >>> a = round(1229.84, 2) * 100
    >>> int(a) - a
    -0.9999999999854481 #I expected -0.9999999999918100?

6 - 似乎我们可以通过舍入到小数点后两位来摆脱所有这些额外的数字。

>>> round(1229.84, 2) # which is really round(1229.8399999999999181, 2)
1229.84

但是当我们使用int(someNum) - someNum公式来查看隐藏的数字时,它们仍然存在。

>>> a = round(1229.84, 2)
>>> int(a) - a
-0.8399999999999181

这是因为Python无法将1229.84存储为二进制浮点数。它无法完成。所以...舍入1229.84绝对没有。

答案 1 :(得分:2)

不要使用浮点运算作为货币;无法准确表示的值的舍入误差将导致您看到的损失类型。相反,将字符串表示转换为整数分数,您可以根据需要将其转换为欧元和美分进行显示。

euros, cents = '12,1'.split(',')     # '12,1' -> ('12', '1')
cents = 100*int(euros) + int(cents * 10 if len(cents) == 1 else 1)  # ('12', '1') -> 1210

(请注意,您需要一张支票来处理美分而不会跟踪0。)

display_str = '%d,%d' % divMod(cents, 100) # 1210 -> (12, 10) -> '12.10'

您还可以使用Decimal模块中的decimal类,它基本上封装了使用整数表示小数值的所有逻辑。

答案 2 :(得分:1)

正如@wim在评论中提到的那样,使用stdlib Decimal模块中的decimal类型而不是内置的float类型。 Decimal个对象没有浮点数所具有的二进制舍入行为,并且具有可由用户定义的精度。

Decimal应该用于您进行财务计算的任何地方,或者您需要浮点计算的任何地方,其行为类似于人们在学校学习的十进制数学(与内置的{(1)的二进制浮点行为相反}} type。。