Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以任意精度将浮点数四舍五入的python方法_Python_Floating Point_Decimal_Rounding - Fatal编程技术网

以任意精度将浮点数四舍五入的python方法

以任意精度将浮点数四舍五入的python方法,python,floating-point,decimal,rounding,Python,Floating Point,Decimal,Rounding,首先,我想提一提的是,这个问题并不是重复的: 我知道IEEE 754,我知道: 简单的“始终向上取整0.5”技术会导致稍微偏向更高的数字。对于大量的计算,这可能非常重要。Python 3.0方法消除了这个问题 我同意ROUND_HALF_UP方法不如Python中默认实现的方法。尽管如此,还是有人不知道这一点,如果规范要求,就需要使用这种方法。实现这一目标的简单方法是: def round_my(num, precission): exp = 2*10**(-precission)

首先,我想提一提的是,这个问题并不是重复的:

我知道IEEE 754,我知道:

简单的“始终向上取整0.5”技术会导致稍微偏向更高的数字。对于大量的计算,这可能非常重要。Python 3.0方法消除了这个问题

我同意ROUND_HALF_UP方法不如Python中默认实现的方法。尽管如此,还是有人不知道这一点,如果规范要求,就需要使用这种方法。实现这一目标的简单方法是:

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
问题在于,这不会通过所有测试用例:

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这样的指数不起作用。有没有类似蟒蛇的方法


我知道我可以加上无穷小的数字,而
四舍五入(num+10**(precision-20),-pricision)
会起作用,但这是错误的,以至于“小狗会死”…

正如你所说,如果你试图用大于
1的数字来计算,那是行不通的:

>>> Decimal('1.5').quantize(Decimal('10'))
Decimal('2')
>>> Decimal('1.5').quantize(Decimal('100'))
Decimal('2')
但您可以简单地进行除法、量化和乘法:

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
但是,只有在输入
十进制
并与
十进制
进行比较时,才能通过测试:

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')

如评论中所述,可以使用科学符号小数作为“工作”量化参数,从而简化函数:

def round_my(num, precision):
    quant_level = Decimal('1e{}'.format(precision))
    return Decimal(num).quantize(quant_level, ROUND_HALF_UP) 
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))

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

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

def round_my(num, precision):
    quant_level = Decimal('1e{}'.format(precision))
    return Decimal(num).quantize(quant_level, ROUND_HALF_UP) 
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))

你知道,例如
1.65
不符合“四舍五入”的条件,因为它实际上是
1.6499999999911182158029987…
?我知道-这就是为什么我写了:“因为浮点和十进制之间的转换性质”-但你是对的,我应该更精确一些。另一方面,我现在想知道,我可能应该省略浮点数,然后对十进制数执行所有计算……不,这不是问题所在。问题是您根本没有
float
s。无法恢复创建浮点的字符串。在您的代码中,将它们作为字符串或小数保存,以避免“一”字陷阱-在您提出您的答案之前,我已将我的答案添加到EDDITE中。。。是的-你是对的。。。您的answear解决了这个问题。使用
Decimal('1e1')
而不是
Decimal('10')
进行量化应该可以像预期的那样工作。@MarkDickinson似乎可以工作。我有点惊讶,你知道为什么会这样吗?
quantize
方法使用第二个参数的指数来确定如何量化。这是一个有点奇怪的设计,但是它是
decimal
模块所基于的规范中的内容。(因此,使用
Decimal('2e1')
Decimal('13e1')
进行量化也会起作用。)您的方法总是返回一个
Decimal
,而它们可能会返回输入类型。@Boris您总是可以再次将其转换为其他类型。然而,转换十进制->浮动可能会导致精度的损失,所以如果你真的想要这样的话,你应该考虑一下。