Python是否具有java.lang.Math.nextUp的等价物?

rli*_*bby 5 python floating-point

我有一个Python float,我想拥有float1个ULP更大更小的s .

在Java中,我会用Math.nextUp(x)和来做Math.nextAfter(x, Double.NEGATIVE_INFINITY).

有没有办法在Python中执行此操作?我想过自己实现它math.frexp,math.ldexp但据我所知,Python没有指定浮点类型的大小.

jfs*_*jfs 5

更新:在 Python 3.9+ 中,有math.nextafter()

>>> import math
>>> x = 4
>>> math.nextafter(x, math.inf)
4.000000000000001
Run Code Online (Sandbox Code Playgroud)

旧答案:

你可以看看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')
Run Code Online (Sandbox Code Playgroud)

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

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

备择方案:

  • 使用以下命令调用C99nextafter()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)
    
    Run Code Online (Sandbox Code Playgroud)

    使用numpy

      >>> import numpy
      >>> numpy.nextafter(4, float('+inf'))
      4.0000000000000009
      >>> _.as_integer_ratio()
      (4503599627370497, 1125899906842624)
    
    Run Code Online (Sandbox Code Playgroud)

    尽管不同repr(),但结果是一样的。

  • 如果我们忽略边缘情况,那么@S.Lott 答案中的一个简单的 frexp/ldexp 解决方案就可以工作:

      >>> 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)
    
    Run Code Online (Sandbox Code Playgroud)
  • next_after(x, y) @Mark Dickinson 的纯 Python实现考虑了边缘情况。在本例中结果是相同的。


Art*_*par 1

我不确定这是否是您想要的,但是sys.float_info.epsilon“1 和大于 1 的最小值之间的差异可以表示为浮点数”,您可以这样做x * (1 + sys.float_info.epsilon)

http://docs.python.org/library/sys.html#sys.float_info