首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有任意精度的ROUND_HALF_UP浮动的Pythonic方法

具有任意精度的ROUND_HALF_UP浮动的Pythonic方法
EN

Stack Overflow用户
提问于 2017-07-13 14:19:20
回答 2查看 1.6K关注 0票数 4

首先,我想提一提,这个问题并非重复:

Python舍入不一致

Python3.x舍入行为

我知道IEEE 754,我知道:

简单的“总是四舍五入”的技术会导致稍微偏向更高的数字。通过大量的计算,这可能是非常重要的。Python3.0方法消除了这个问题。

我同意ROUND_HALF_UP方法比默认情况下在Python中实现的方法要差。然而,有些人不知道这一点,如果规格要求的话,就需要使用这种方法。让这项工作发挥作用的简单方法是:

代码语言:javascript
复制
def round_my(num, precission):
    exp  = 2*10**(-precission)
    temp = num * exp
    if temp%2 < 1:
        return int(temp - temp%2)/exp
    else:
        return int(temp - temp%2 + 2)/exp

但我的考虑是这不是毕达通..。根据文档,我应该使用如下内容:

代码语言:javascript
复制
def round_my(num, pricission):
    N_PLACES = Decimal(10) ** pricission       # same as Decimal('0.01')
    # Round to n places
    Decimal(num).quantize(N_PLACES)

问题是,这并不能通过所有测试用例:

代码语言:javascript
复制
class myRound(unittest.TestCase):
    def test_1(self):
        self.assertEqual(piotrSQL.round_my(1.53, -1), 1.5)
        self.assertEqual(piotrSQL.round_my(1.55, -1), 1.6)
        self.assertEqual(piotrSQL.round_my(1.63, -1), 1.6)
        self.assertEqual(piotrSQL.round_my(1.65, -1), 1.7)
        self.assertEqual(piotrSQL.round_my(1.53, -2), 1.53)
        self.assertEqual(piotrSQL.round_my(1.53, -3), 1.53)
        self.assertEqual(piotrSQL.round_my(1.53,  0), 2)
        self.assertEqual(piotrSQL.round_my(1.53,  1), 0)
        self.assertEqual(piotrSQL.round_my(15.3,  1), 20)
        self.assertEqual(piotrSQL.round_my(157.3,  2), 200)

由于浮点数和十进制之间转换的性质,以及量化似乎不适用于像10或100这样的指数。有什么毕达通的方法吗?

我知道我可以添加无穷小的数字,round(num+10**(precission-20),-pricission)会工作,但这是错误的,以至于“小狗会死”.

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-13 14:46:58

就像你说的,如果你试图用大于quantize1数,那是行不通的。

代码语言:javascript
复制
>>> Decimal('1.5').quantize(Decimal('10'))
Decimal('2')
>>> Decimal('1.5').quantize(Decimal('100'))
Decimal('2')

但你可以简单地除以,量化和乘:

代码语言:javascript
复制
from decimal import Decimal, ROUND_HALF_UP

def round_my(num, precision):
    N_PLACES = Decimal(10) ** precision
    # Round to n places
    return (Decimal(num) / N_PLACES).quantize(1, ROUND_HALF_UP) * N_PLACES

但是,只有在输入Decimal并与Decimal进行比较时,才能通过测试。

代码语言:javascript
复制
assert round_my('1.53', -1) == Decimal('1.5')
assert round_my('1.55', -1) == Decimal('1.6')
assert round_my('1.63', -1) == Decimal('1.6')
assert round_my('1.65', -1) == Decimal('1.7')
assert round_my('1.53', -2) == Decimal('1.53')
assert round_my('1.53', -3) == Decimal('1.53')
assert round_my('1.53',  0) == Decimal('2')
assert round_my('1.53',  1) == Decimal('0')
assert round_my('15.3',  1) == Decimal('20')
assert round_my('157.3',  2) == Decimal('200')

正如注释中所指出的,可以使用科学符号小数作为“工作”量化参数,这简化了函数:

代码语言:javascript
复制
def round_my(num, precision):
    quant_level = Decimal('1e{}'.format(precision))
    return Decimal(num).quantize(quant_level, ROUND_HALF_UP) 

这也通过了上面提到的测试用例。

票数 3
EN

Stack Overflow用户

发布于 2020-11-05 19:38:20

下面是一个与内置round()函数的行为和API相匹配的版本:

代码语言:javascript
复制
from decimal import Decimal, ROUND_HALF_UP

def round_half_up(number, ndigits=None):
    return_type = type(number)
    if ndigits is None:
        ndigits = 0
        return_type = int
    if not isinstance(ndigits, int):
        msg = f"'{type(ndigits).__name__}' object cannot be interpreted as an integer"
        raise TypeError(msg)
    quant_level = Decimal(f"10E{-ndigits}")
    return return_type(Decimal(number).quantize(quant_level, ROUND_HALF_UP))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45083399

复制
相关文章

相似问题

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