首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SymPy舍入行为

SymPy舍入行为
EN

Stack Overflow用户
提问于 2018-02-20 22:28:57
回答 3查看 2.1K关注 0票数 2

我正在使用Python内置解决方案和其他一些外部库(如SymPy )研究不同的舍入方法,在这样做的过程中,我偶然发现了一些需要帮助的案例,以帮助我理解其背后的原因。

前例1:

代码语言:javascript
复制
print(round(1.0065,3))

输出: 1.006

在第一种情况下,使用Python内置的舍入函数,输出是1.006而不是1.007,我可以理解这不是一个错误,因为Python舍入到了最接近的偶数,这就是所谓的银行家舍入。

这就是为什么我从一开始就开始寻找另一种方法来控制舍入行为。通过快速搜索,我找到了decimal.Decimal模块,它可以轻松地处理十进制值,并有效地使用quantize()进行舍入,如下例所示:

代码语言:javascript
复制
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提供了一些非常强大的功能,这些功能可能会有所帮助,但当我尝试它时,输出并不像我预期的那样。

使用SymPy渐近()的Ex-1:

代码语言:javascript
复制
print(sympify(1.0065).evalf(3))

输出: 1.01

Ex-2使用SymPy N(规格化):

代码语言:javascript
复制
print(N(1.0065,3))

输出: 1.01

首先,输出有点奇怪,但在研究之后,我意识到N和渐近已经执行了四舍五入,但四舍五入到了有意义的数字,而不是小数位。

问题来了:

正如我可以使用Decimal对象getcontext().round with =‘ROUND_HALF_UP’来改变舍入行为,有没有一种方法可以将N和渐近舍入行为更改为小数位而不是有效数字?

EN

回答 3

Stack Overflow用户

发布于 2018-02-20 23:03:20

可以使用decimal进行舍入,但在实用函数中隐藏计算,而不是在SymPy中重新实现小数舍入:

代码语言:javascript
复制
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))

打印

代码语言:javascript
复制
0.007
1.007
10.007
100.007    
票数 1
EN

Stack Overflow用户

发布于 2018-02-20 23:17:21

首先,Nevalf本质上是一回事;N(x, n)等同于sympify(x).evalf(n)。在本例中,因为x是Python浮点型,所以使用N更容易,因为它对输入进行了表示。

要获取小数点后的三位数,请使用N(x, 3 + log(x, 10) + 1)。当x在0.1和1之间时,调整log(x, 10) + 1为0;在这种情况下,有效位数与小数点后的位数相同。如果x越大,我们得到的有效数字就越多。

示例:

代码语言:javascript
复制
for x in [0.0065, 1.0065, 10.0065, 100.0065]:
    print(N(x, 3 + log(x, 10) + 1))

打印

代码语言:javascript
复制
0.006
1.007
10.007
100.007

从6到7的过渡很奇怪,但并不完全令人惊讶。这些数字不是用二进制精确表示的,所以截断到最接近的双精度浮点数可能是这里的一个因素。我在这个效果上做了一些额外的观察,on my blog

票数 0
EN

Stack Overflow用户

发布于 2018-02-21 08:40:23

evalf的n给出了x的前n个有效数字(从左开始测量)。如果使用x.round(3),它会将x舍入到从小数点开始的第n位,并且可以是正(小数点pt的右边)或负数(小数点pt的左边)。

代码语言:javascript
复制
>>> 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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48887515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档