我必须将欧元(字符串)翻译成欧元美分(int):
示例:
我使用这个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先生解答,他解释了上述结果。
答案 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。。