Имеет ли Python эквивалент java.lang.Math.nextUp?

У меня есть плагин Python, и я хочу иметь float с 1 ULP больше и меньше.

В Java я бы сделал это с помощью Math.nextUp(x) и Math.nextAfter(x, Double.NEGATIVE_INFINITY) .

Есть ли способ сделать это в Python? Я подумал о том, чтобы реализовать его самостоятельно с помощью math.frexp и math.ldexp но насколько я знаю, Python не указывает размер типов с плавающей запятой.

Вы можете посмотреть, как 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]) 

Альтернативы:

  • Вызовите C99 nextafter() используя 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) 

    Использование numpy :

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

    Несмотря на разное repr() , результат тот же.

  • Если мы игнорируем случаи краев, то простое решение frexp / ldexp из ответа @ S.Lott работает:

     >>> 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) 
  • чистая реализация Python next_after(x, y) by @Mark Dickinson, которая учитывает краевые случаи. В этом случае результат будет таким же.

Я не уверен, что это то, что вы хотите, но sys.float_info.epsilon – это «разница между 1 и наименьшим значением больше 1, которое представляется как float», и вы могли бы сделать x * (1 + sys.float_info.epsilon) .

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