PEP 238 , «Смена оператора подразделения», я думаю, хорошо объясняет проблемы. Вкратце: когда Python был спроектирован, он принял «усеченное» значение для /
между целыми числами, просто потому, что большинство других языков программирования делали это с тех пор, как в 1957 году был запущен первый компилятор FORTRAN (имя из всех прописных букв и все ;-) (Одним широко распространенным языком, который не принял это значение, используя /
для получения результата с плавающей запятой и div
для усечения, был Pascal).
В 2001 году было решено, что этот выбор не является оптимальным (цитируя PEP: «Это делает выражения, ожидающие плавающие или сложные результаты подверженными ошибкам, когда целые числа не ожидаются, но возможны в качестве входных данных»), и переключиться на использование новый оператор //
для запроса деления с усечением и изменения значения /
для получения результата с плавающей запятой («истинное деление»).
Вы можете явно запросить это поведение, поместив оператор
from __future__ import division
в начале модуля (переключение командной строки -Q
на интерпретатор python
также может управлять поведением деления). В отсутствие такого «импорта из будущего» (и использования переключателя командной строки) Python 2.x для всех значений x всегда использует «классическое деление» (т. Е. /
усекается между int
с).
Python 3, однако, всегда использует «истинное деление» (/
между int
s производит float
).
Обратите внимание на любопытное следствие (в Python 3) ...:
>>> from fractions import Fraction
>>> Fraction(1/2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/fractions.py", line 100, in __new__
raise TypeError("argument should be a string "
TypeError: argument should be a string or a Rational instance
, поскольку /
создает float
, это не приемлемо в качестве аргумента для Fraction
(в противном случае точность может быть молча потеряна) Вы должны использовать строку или передать числитель и знаменатель в качестве отдельных аргументов:
>>> Fraction(1, 2)
Fraction(1, 2)
>>> Fraction('1/2')
Fraction(1, 2)
gmpy использует другой, более терпимый подход к построению mpq
s, его эквивалент Python 3 Fraction
s ...:
>>> import gmpy
>>> gmpy.mpq(1/2)
mpq(1,2)
В частности (см. Строки 3168 и далее в источник ), gmpy использует дерево Штерна-Броко , чтобы получить «наилучшее практическое приближение» аргумента с плавающей точкой в качестве рационального (конечно, эта может маскировать потерю точности).