我正在研究使用Python内置解决方案和其他一些外部库(如SymPy)的不同舍入方法,在这样做时我偶然发现了一些需要帮助的案例,以了解其背后的原因。
实施例1:
print(round(1.0065,3))
输出: 1.006
在第一种情况下,使用Python内置的舍入函数输出为1.006而不是1.007我可以理解这不是一个错误,因为Python舍入到最近的偶数并且被称为Bankers四舍五入
这就是为什么我从一开始就开始寻找另一种方法来控制舍入行为。通过快速搜索,我发现decimal.Decimal模块可以轻松处理十进制值并有效舍入使用quantze(),如下例所示:
from decimal import Decimal, getcontext, ROUND_HALF_UP
context= getcontext()
context.rounding='ROUND_HALF_UP'
print(Decimal('1.0065').quantize(Decimal('.001')))
输出:1.007
这是一个非常好的解决方案,但唯一的问题是在长数学表达式中进行硬编码并不容易,因为我需要将每个数字转换为字符串然后在使用十进制之后我会将它传递给进程中的进动形式为" 0.001"而不是写'' 3'直接就像内置圆形一样。
在寻找另一个解决方案时,我发现SymPy,我已经在我的脚本中使用了很多,提供了一些非常强大的功能,可能会有所帮助但是当我尝试它时,输出并不像我预期的那样。
Ex-1使用SymPy sympify():
print(sympify(1.0065).evalf(3))
输出:1.01
使用SymPy N(标准化)的Ex-2:
print(N(1.0065,3))
输出:1.01
首先,输出有点奇怪,但在调查后我意识到N和同意已经执行了右轮但是四舍五入到有效数字,而不是小数位。问题来了:
因为我可以使用Decimal对象getcontext()。rounding =' ROUND_HALF_UP'要改变舍入行为,有没有办法改变N并将舍入行为与小数位相提并论,而不是有效数字?
答案 0 :(得分:0)
不是在SymPy中重新实现十进制舍入,而是使用decimal
进行舍入,但是在实用程序函数中隐藏计算:
import sympy as sym
import decimal
from decimal import Decimal as D
def dround(d, ndigits, rounding=decimal.ROUND_HALF_UP):
result = D(str(d)).quantize(D('0.1')**ndigits, rounding=rounding)
# result = sym.sympify(result) # if you want a SymPy Float
return result
for x in [0.0065, 1.0065, 10.0065, 100.0065]:
print(dround(x, 3))
打印
0.007
1.007
10.007
100.007
答案 1 :(得分:0)
首先,N
和evalf
基本相同; N(x, n)
相当于sympify(x).evalf(n)
。在您的情况下,由于x是Python float,因此它更容易使用N
,因为它与输入相符。
要获得小数点后的三位数,请使用N(x, 3 + log(x, 10) + 1)
。当x在0.1和1之间时,调整log(x, 10) + 1
为0;在这种情况下,有效位数与小数点后的位数相同。如果x更大,我们会得到更多有效数字。
示例:
for x in [0.0065, 1.0065, 10.0065, 100.0065]:
print(N(x, 3 + log(x, 10) + 1))
打印
0.006
1.007
10.007
100.007
从6到7的过渡很奇怪,但并不完全令人惊讶。这些数字在二进制系统中并不完全表示,因此截断到最近的双精度浮点数可能是一个因素。我对此效果进行了一些额外的观察on my blog。
答案 2 :(得分:0)
evalf
的n给出x的前n个有效数字(从左边开始测量)。如果你使用x.round(3)它会将x从小数点舍入到第n位,可以是正数(小数点右边)或负数(小数点左边)。
>>> for x in '0.0065, 1.0065, 10.0065, 100.0065'.split(', '):
... print S(x).round(3)
0.006
1.006
10.007
100.007
>>> int(S(12345).round(-2))
12300