Лучший способ узнать, является ли число дробным или нет

Я хочу различать такие числа, как 2.0 или 2 и действительное дробное число, такое как 2.4. Как лучше всего это сделать? В настоящее время занимаюсь:

def is_fractional(num):
    if not str(num).replace('.','').isdigit(): return
    return float(num) != int(num)

>>> is_fractional(2)
False
>>> is_fractional(2.1)
True
>>> is_fractional(2.0)
False
>>> is_fractional('a')
>>>

Может abs(x - int(x)) > 0?

John Coleman 27.10.2018 02:58
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
1
355
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Почему бы не проверить, не равна ли разность между усечением до целого числа и точным значением нулю?

is_frac = lambda x: int(x)-x != 0
Ответ принят как подходящий

Эта операция встроена:

>>> 5.0.is_integer()
True
>>> 5.00000001.is_integer()
False
>>> 4.9999999.is_integer()
False

Документация - здесь.

ДОБАВЛЕНИЕ

Первоначальное решение работает только для float. Вот более полный ответ с тестами:

from decimal import Decimal

def is_integer(x):
    if isinstance(x, int):
        return True
    elif isinstance(x, float):
        return x.is_integer()
    elif isinstance(x, Decimal):
        return x.as_integer_ratio()[1] == 1
    return False

good = [
    0, 
    0.0, 
    3, 
    -9999999999999999999999, 
    -2.0000000000000,
    Decimal("3.000000"),
    Decimal("-9")
]
bad = [
    -9.99999999999999,
    "dogs",
    Decimal("-4.00000000000000000000000000000000001"),
    Decimal("0.99999999999999999999999999999999999")
]

for x in good:
    assert is_integer(x)
for x in bad:
    assert not is_integer(x)
print("All tests passed")

Проблема с этим подходом в том, что я часто имею дело с десятичными знаками, поэтому мне нужно сначала использовать его. В противном случае получаю: AttributeError: 'decimal.Decimal' object has no attribute 'is_integer'

David542 27.10.2018 03:28

Хорошая точка зрения. is_integer существует только на float. Для Decimal я бы выбрал d.as_integer_ratio()[1] == 1.

Ray Toal 27.10.2018 04:22

Обновил ответ

Ray Toal 27.10.2018 04:30

Ах, as_integer_ratio лучше, чем as_tuple, с подсчетом нулей в конце. +1

torek 27.10.2018 20:16

Думаю, да ... Я попробовал несколько методов decimal.Decimal и обнаружил, что этот метод особенно хорош и работает для всего, что я к нему применил. Неограниченные целые числа в Python так хороши.

Ray Toal 27.10.2018 20:29

@RayToal дополнительно, почему происходит что-то вроде >>> float(-9999999999999999999999)==int(-9999999999999999999999) >>> False?

David542 28.10.2018 00:11

Поплавки не имеют произвольной точности! Они хранятся в 64-битном формате с 53 битами мантиссы, что составляет 15-17 значащих цифр. Если вы оцените float(-9999999999999999999999) на Python, вы получите -1e+22. Значение -9999999999999999999999 просто не может быть представлено в 64-битном IEEE 754. Ближайшее представимое значение - -10000000000000000000000. Но в типе int все числа представимы.

Ray Toal 28.10.2018 03:03

Если вы имеете дело с модулем decimal или объектом float, вы можете сделать это легко:

def is_factional(num):
    return isinstance(num, (float, Decimal))

Если некоторые из ваших чисел являются числами decimal.Decimal, у них могут быть проблемы с диапазоном, когда преобразование в число с плавающей запятой не удается или отбрасывает существующую дробную часть, в зависимости от их точности:

>>> import decimal
>>> x = decimal.Decimal('1.00000000000000000000000000000000000001')
>>> str(x)
'1.00000000000000000000000000000000000001'
>>> float(x).is_integer()
True

>>> y = decimal.Decimal('1e5000')
>>> str(y)
'1E+5000'
>>> float(y)
inf

Метод str обычно работает (по модулю проблемных случаев, подобных показанному выше), поэтому вы можете придерживаться его, но может быть лучше попытаться использовать is_integer и использовать запасной вариант, если это не поможет:

try:
   return x.is_integer()
except AttributeError:
   pass

(как отмечают другие, вам также необходимо проверить здесь int и long, если это разрешенные типы, поскольку они являются целыми числами по определению, но не имеют атрибута is_integer).

На этом этапе стоит рассмотреть все остальные ответы, но вот конкретный обработчик decimal.Decimal:

# optional: special case decimal.Decimal here
try:
    as_tuple = x.as_tuple()
    trailing0s = len(list(itertools.takewhile(lambda i: i == 0, reversed(as_tuple[1]))))
    return as_tuple[2] + trailing0s < 0
except (AttributeError, IndexError): # no as_tuple, or not 3 elements long, etc
    pass

Вот один из способов сделать это (при условии, например, что 2/2 не является «дробным» в том смысле, который вы имеете в виду):

# could also extend to other numeric types numpy.float32 
from decimal import Decimal

def is_frac(n):
  numeric_types = (int, float, Decimal)
  assert isinstance(n, numeric_types), 'n must be numeric :/'
  # (ints are never fractions)
  if type(n) is int: return False
  return n != float(int(n))

# various sorts of numbers 
ns = [-1, -1.0, 0, 0.1, 1, 1.0, 1., 2.3, 1e0, 1e3, 1.1e3, 
      Decimal(3), Decimal(3.0), Decimal(3.1)]

# confirm that values are as expected 
dict(zip(ns, [is_frac(n) for n in ns]))

Это будет работать, только если n - это int, float или decimal.Decimal. Но вы можете расширить его для обработки других числовых типов, таких как numpy.float64 или numpy.int32, просто включив их в numeric_types.

Python включает модуль fractions, который генерирует дроби (рациональные числа) из строк, float, целых чисел и многого другого. Просто создайте Fraction и проверьте, отличен ли его знаменатель от 1 (конструктор Fraction автоматически уменьшит число до наименьших членов):

from fractions import Fraction

def is_fractional(num):
    return Fraction(num).denominator != 1

Обратите внимание, что описанный выше метод может вызвать исключение, если преобразование в Fraction завершится неудачно. В этом случае неизвестно, является ли объект дробным.

Другие вопросы по теме