Есть ли способ вернуть полностью уменьшенное соотношение при вызове .as_integer_ratio ()? - PullRequest
0 голосов
/ 21 ноября 2018

Я заметил кое-что странное, когда вызывал .as_integer_ratio () на некоторых поплавках.например:

(2.2).as_integer_ratio()

Это вернет кортеж: (2476979795053773, 1125899906842624)

Мне было интересно, могу ли я заставить его возвращать 11/5 напрямую каким-то образом?

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Ответ @ShadowRanger правильный.Значение «2.2» преобразуется в ближайшую двоичную дробь.И .as_integer_ratio() возвращает эту двоичную дробь.Однако есть и другие близкие рациональные числа, которые приводят к тому же двоичному представлению при преобразовании в число с плавающей точкой.Можно найти более простую дробь, используя дерево Stern-Brocot .

gmpy2 имеет реализацию алгоритма Stern-Brocot и отображается как .as_simple_fraction().

>>> gmpy2.mpfr("2.2").as_integer_ratio()
(mpz(2476979795053773), mpz(1125899906842624))
>>> gmpy2.mpfr("2.2").as_simple_fraction()
mpq(11,5)
0 голосов
/ 21 ноября 2018

Плавающая точка на самом деле не может представлять большинство значений, набираемых .2.2 - это удобное сокращение для ближайшего значения к 2.2, но 2.2 на самом деле не существует:

>>> print('{:.16f}'.format(2.2))
2.2000000000000002

Если вы хотите получить представление с десятичной точностью, вам нужно использовать модуль decimal вместо float:

>>> from decimal import Decimal
>>> Decimal('2.2').as_integer_ratio()  # Constructing from str is *mandatory* for proper precision
(11, 5)
...