将float转换为四舍五入的十进制数

编程入门 行业动态 更新时间:2024-10-18 10:35:20
本文介绍了将float转换为四舍五入的十进制数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

当您将浮动转换为十进制时,十进制将包含它可以准确表示的二进制数。准确是很好的,但并不总是你想要的。由于很多十进制数不能完全用二进制表示,因此产生的 Decimal 会稍微偏离 - 有时会有点高,有时会有点低。

>>> from decimal import Decimal >>> f(0.1,0.3,1e25,1e28,1.0000000000001): print十进制(f) 0.1000000000000000055511151231257827021181583404541015625 0.299999999999999988897769753748434595763683319091796875 10000000000000000905969664 9999999999999999583119736832 1.000000000000099920072216264088638126850128173828125

理想情况下,我们希望 Decimal 我试图转换为 str ,因为 Decimal 将是精确的。不幸的是 str 有点太过分了。

>>> ;对于f in(0.1,0.3,1e25,1e28,1.0000000000001): print十进制(str(f)) 0.1 0.3 1E + 25 1E + 28 1.0

有没有办法让一个很好的四舍五入 Decimal 从一个浮点数?

解决方案

事实证明, > repr 将 float 转换为比 str 更好的字符串。

>>>这是快速简单的转换方式。对于f in(0.1,0.3,1e25,1e28,1.0000000000001): print十进制(repr(f)) 0.1 0.3 1E + 25 1E + 28 1.0000000000001

在我发现之前,四舍五入的方法。它具有识别大数字精确到15位的优势 - 上面的 repr 方法只能识别1e25和1e28示例的一个有效数字。

从十进制导入Decimal,DecimalTuple def _increment(数字,指数): new_digits = [0] + (len(new_digits)-1,0,-1):如果new_digits [i]>列表(数字) new_digits [-1] + = 1 9: new_digits [i] - = 10 new_digits [i-1] + = 1 如果new_digits [0]:返回元组(new_digits [: - 1]) ,指数+ 1 返回元组(new_digits [1:]),指数 最接近的十进制(f):符号,数字,指数=十进制(f).as_tuple ) len(数字)> 15: round_up = digits [15]> = 5 exponent + = len(digits) - 15 digits = digits [:15] 如果round_up:数字,指数= _增量(数字,指数)数字和数字[-1] == 0和指数< 0: digits = digits [: - 1] 指数+ = 1 返回十进制(DecimalTuple(sign,digits,exponent)) >> > for f in(0.1,0.3,1e25,1e28,1.0000000000001): print nearest_decimal(f) 0.1 0.3 1.00000000000000E + 25 1.00000000000000E + 28 1.0000000000001

编辑:更多的理由使用蛮力四舍五入。 repr 尝试返回一个字符串,该字符串唯一标识了底层的 float 位表示形式,但并不一定确保准确性最后一位数字。

>>>通过使用少一个数字,我的舍入函数更经常是您期望的数字。打印Decimal(repr(2.0 / 3.0)) 0.6666666666666666 >>> print dec.nearest_decimal(2.0 / 3.0) 0.666666666666667

$ c> repr 实际上是更准确的,但它意味着不存在的精度级别。 nearest_decimal 函数在精度和精度之间提供了更好的匹配。

When you convert a float to Decimal, the Decimal will contain as accurate a representation of the binary number that it can. It's nice to be accurate, but it isn't always what you want. Since many decimal numbers can't be represented exactly in binary, the resulting Decimal will be a little off - sometimes a little high, sometimes a little low.

>>> from decimal import Decimal >>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001): print Decimal(f) 0.1000000000000000055511151231257827021181583404541015625 0.299999999999999988897769753748434595763683319091796875 10000000000000000905969664 9999999999999999583119736832 1.000000000000099920072216264088638126850128173828125

Ideally we'd like the Decimal to be rounded to the most likely decimal equivalent.

I tried converting to str since a Decimal created from a string will be exact. Unfortunately str rounds a little too much.

>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001): print Decimal(str(f)) 0.1 0.3 1E+25 1E+28 1.0

Is there a way of getting a nicely rounded Decimal from a float?

解决方案

It turns out that repr does a better job of converting a float to a string than str does. It's the quick-and-easy way to do the conversion.

>>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001): print Decimal(repr(f)) 0.1 0.3 1E+25 1E+28 1.0000000000001

Before I discovered that, I came up with a brute-force way of doing the rounding. It has the advantage of recognizing that large numbers are accurate to 15 digits - the repr method above only recognizes one significant digit for the 1e25 and 1e28 examples.

from decimal import Decimal,DecimalTuple def _increment(digits, exponent): new_digits = [0] + list(digits) new_digits[-1] += 1 for i in range(len(new_digits)-1, 0, -1): if new_digits[i] > 9: new_digits[i] -= 10 new_digits[i-1] += 1 if new_digits[0]: return tuple(new_digits[:-1]), exponent + 1 return tuple(new_digits[1:]), exponent def nearest_decimal(f): sign, digits, exponent = Decimal(f).as_tuple() if len(digits) > 15: round_up = digits[15] >= 5 exponent += len(digits) - 15 digits = digits[:15] if round_up: digits, exponent = _increment(digits, exponent) while digits and digits[-1] == 0 and exponent < 0: digits = digits[:-1] exponent += 1 return Decimal(DecimalTuple(sign, digits, exponent)) >>> for f in (0.1, 0.3, 1e25, 1e28, 1.0000000000001): print nearest_decimal(f) 0.1 0.3 1.00000000000000E+25 1.00000000000000E+28 1.0000000000001

Edit: I discovered one more reason to use the brute-force rounding. repr tries to return a string that uniquely identifies the underlying float bit representation, but it doesn't necessarily ensure the accuracy of the last digit. By using one less digit, my rounding function will more often be the number you would expect.

>>> print Decimal(repr(2.0/3.0)) 0.6666666666666666 >>> print dec.nearest_decimal(2.0/3.0) 0.666666666666667

The decimal created with repr is actually more accurate, but it implies a level of precision that doesn't exist. The nearest_decimal function delivers a better match between precision and accuracy.

更多推荐

将float转换为四舍五入的十进制数

本文发布于:2023-11-10 02:42:53,感谢您对本站的认可!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:转换为   四舍五入   十进制数   float

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!