python中的默认舍入模式,如何将其指定为另一个?

Default rounding mode in python, and how to specify it to another one?

Python 中的默认舍入模式(舍入到最接近的值等)是什么?我们如何指定它?

round() 是内置的舍入函数。它的工作原理如下:

轮(数[ ndigits])

它return是你用 ndigits 小数四舍五入的浮点型数字

值四舍五入到最接近的 10 的乘方减去 ndigits 的倍数;如果两个倍数同样接近,则向偶数选择进行舍入(例如,round(0.5) 和 round(-0.5) 均为 0,而 round(1.5) 为 2)。如果使用一个参数调用,return 值是一个整数,否则与数字类型相同。

限制: https://docs.python.org/3/tutorial/floatingpoint.html#tut-fp-issues

来源: https://docs.python.org/3/library/functions.html

对于基于 IEEE754 的平台(就像大多数现代平台一样,包括 x86、ARM、MIPS...),它的默认模式 "round to nearest, ties to even" 是 Python 标准库中唯一可用的模式。这是 "provided" 通过标准化默认值和缺少库方法来更改它。还有更多不允许更改舍入模式的语言 - 例如Java - 所以这不是孤立的 Python 一时兴起。

实际上,改变这个的理由太少了。 IEEE754 的直接舍入模式在使用上非常特殊。 (我不会为坚持默认舍入的方法道歉,只是简单地评论一下。)例如,将 1e308 乘以 1e308 并舍入到零或负无穷大的结果大约为 1.8e308,因此,结果太与确切答案和基于 POLA 的答案(无穷大)相去甚远。如果您确实需要一些特定的计算模式,请考虑使用特定的库,例如 MPFR 或 gmpy2。

如果您坚持在没有专门用于浮点计算的外部模块的情况下更改它,请尝试通过 ctypes 模块或模拟使用 C 库 fesetround,例如here。同样,您可以选择使用此类黑客手段并对所有后果负责。我建议将所有带有特殊舍入的部分包装成 C 级代码,这样可以在函数退出时恢复默认模式。

接受的答案并不完全正确。当有人询问舍入模式时,浮点数可能是您首先想到的,但它们不是您应该查看的地方。

原因很简单:四舍五入是为了让答案的位数更少。每当你提到数字时,你必须确定你在谈论什么基数。我不了解你的具体情况,但当人们谈到数字时,他们通常指的是 decimal 数字。为此,浮点数显然是不够的,因为它们有 binary 数字。您不能将浮点数 0.12 舍入为一位十进制数字,因为它没有意义:尽管外观如此,但它没有那种数字。 :-)

当然,您可以做的是尝试通过四舍五入来补偿浮点数的小数不精确性,以便过冲和下冲以最佳方式相互抵消,在这种情况下,它已被证明很长以前只有一个正确答案 ROUND_HALF_EVEN---and 它是由 float 提供的(如果你需要它在更高的小数位,则由 round 函数提供)开箱即用。但请注意,它与 'calculating the mean grade'(ROUND_HALF_UP,通常)或 'estimating the mean error'(ROUND_UP),或“给你一个税收等级”(ROUND_FLOOR), 或需要一些固定数量的十进制数字的其他各种特定任务(或者在某些现已失效的货币的情况下,一些其他基数,但通常不是二进制)。

事实上,有一个 Python 标准库模块,它为您提供了所有您可能会觉得有用的舍​​入模式,鉴于以上段落,这是合乎逻辑的地方:当然,它是decimal 模块。它表示浮点数不是以 2 为底,而是以 10 为底,因此,它提供了有意义的可能性,可以使用对特定任务有意义的舍入方法将数字舍入到给定的小数位数。

>>> import statistics, decimal
>>> grades = map(decimal.Decimal, [4, 5])
>>> print(statistics.mean(grades).to_integral_exact(decimal.ROUND_HALF_UP))
5

HTH.

我过去用过这些,没有任何负面影响:

from math import floor, ceil

def round_floor(scale, x):
  return floor(x*(10**scale))/(10**scale)

def round_ceiling(scale,x):
  return ceil(x*(10**scale))/(10**scale)

但我没有考虑过对非常大或非常精确的数字的影响。

>>> round_floor(1,123.456)
123.4
>>> round_floor(-1,123.456)
120.0
>>> round_floor(2,123.456)
123.45

>>> round_ceiling(1,123.456)
123.5
>>> round_ceiling(-1,123.456)
130.0
>>> round_ceiling(-2,123.456)
200.0