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

时间:2011-04-21 20:01:07

标签: python floating-point

我有一个Python float,我希望float的{​​{1}}大一点ULP

在Java中,我会使用Math.nextUp(x)Math.nextAfter(x, Double.NEGATIVE_INFINITY)执行此操作。

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

2 个答案:

答案 0 :(得分:3)

您可以查看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')

确保decimal context具有您需要的值:

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

备选方案:

  • 使用ctypes

    致电C99 nextafter()
    >>> 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)
    

    使用numpy

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

    尽管repr()不同,但结果却相同。

  • 如果我们忽略边缘情况,那么来自@S.Lott answer的简单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)
    
  • 考虑边缘情况的
  • pure Python next_after(x, y) implementation by @Mark Dickinson。在这种情况下结果是相同的。

答案 1 :(得分:1)

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

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