Python是否有类似于java.lang.Math.nextUp的等效函数?

5

1
同样的问题在这里被问到了:http://bytes.com/topic/python/answers/739926-next-float,并得到了好的答案... - Benjamin
2个回答

5

更新:在 Python 3.9+ 中,有一个名为 math.nextafter() 的函数:

>>> import math
>>> x = 4
>>> math.nextafter(x, math.inf)
4.000000000000001

New answer:

您可以查看如何实现 Decimal.next_plus()/Decimal.next_minus()

>>> from decimal import Decimal as D
>>> d = D.from_float(123456.78901234567890)
>>> d
Decimal('123456.789012345674564130604267120361328125')
>>> d.next_plus()
Decimal('123456.7890123456745641306043')
>>> d.next_minus()
Decimal('123456.7890123456745641306042')
>>> d.next_toward(D('-inf'))
Decimal('123456.7890123456745641306042')

确保 十进制上下文 具有您需要的值:

>>> from decimal import getcontext
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
capitals=1, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])

备选方案:

  • Call C99 nextafter() using ctypes:

      >>> import ctypes
      >>> nextafter = ctypes.CDLL(None).nextafter
      >>> nextafter.argtypes = ctypes.c_double, ctypes.c_double
      >>> nextafter.restype = ctypes.c_double
      >>> nextafter(4, float('+inf'))
      4.000000000000001
      >>> _.as_integer_ratio()
      (4503599627370497, 1125899906842624)
    

    Using numpy:

      >>> import numpy
      >>> numpy.nextafter(4, float('+inf'))
      4.0000000000000009
      >>> _.as_integer_ratio()
      (4503599627370497, 1125899906842624)
    

    Despite different repr(), the result is the same.

  • If we ignore edge cases then a simple frexp/ldexp solution from @S.Lott answer works:

      >>> import math, sys
      >>> m, e = math.frexp(4.0)
      >>> math.ldexp(2 * m + sys.float_info.epsilon, e - 1)
      4.000000000000001
      >>> _.as_integer_ratio()
      (4503599627370497, 1125899906842624)
    
  • pure Python next_after(x, y) implementation by @Mark Dickinson that takes into account edge cases. The result is the same in this case.


它看起来不错,但需要一些改进 - 因为Python中的浮点数具有53位的尾数http://docs.python.org/2/tutorial/floatingpoint.html。我认为更好的方法是使用frexp ldexp-可以更快。 - Chameleon
@Chameleon:是的。您可以使用frexp()/ldexp()函数来找到“下一个”数。 - jfs

1

1
这是一个相关的想法,但不完全是我想要的。 对于指数为0,它基本上是正确的,但对于较小的指数来说太大了,对于较大的指数来说又太小了。感谢您指出sys.float_info。至少有了这个结构,我可以可靠地确定底层浮点类型的大小,即使我仍然必须猜测它是否为IEEE-754。有了这个,我可以按照@Benjamin的建议,特别是使用struct模块,找出解决方案。 - rlibby
x + epsilon?那不应该是 x * (1 + epsilon) 吗? - vartec
@vartec 我不知道,但我在答案中进行了更正。 - Artur Gaspar
返回接近于 nextafter(x, float('+inf')) 值的表达式:((2*m+sys.float_info.epsilon)*2**(e-1)),其中 .5 <= m < 1 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接