Почему и как Python усекает числовые данные? - PullRequest
3 голосов
/ 20 апреля 2011

Я имею дело с двумя переменными здесь, но в замешательстве, потому что их значения, кажется, изменяются (они теряют точность), когда я хочу отправить их как параметры URL, как они есть.

Посмотрите на этот сценарий, поскольку я воспроизвожу его здесь из интерпретатора Python:

>>> lat = 0.33245794180134
>>> long = 32.57355093956
>>> lat
0.33245794180133997
>>> long
32.57355093956
>>> nl = str(lat)
>>> nl '0.332457941801'
>>> nlo = str(long)
>>> nlo '32.5735509396'

Так что же происходит? и как я могу гарантировать, что когда я сериализую lat и long в строки и отправлю их как часть строки запроса URL, я не потеряю их точную точность?

Чтобы прояснить ситуацию:

  1. Данные изначально поступают в мой модуль как плавающие (в коллекции) из другого модуля, который создает их из вычислений.
  2. Точность - это чувствительная проблема, потому что эти данные используются для отслеживания и мониторинга сортировок, и неправильные значения могут вызвать ложные срабатывания или ненужные тревоги.
  3. Невозможно отправить данные целевому механизму (который прослушивает через гибкий API) без сериализации данных в строки (поэтому я могу поместить их в строку запроса в качестве параметров)

Итак, что мне было нужно, так это лучший способ преобразовать числа с плавающей точкой в ​​строки с минимальной потерей точности / информации.

Ответы [ 4 ]

4 голосов
/ 20 апреля 2011

Как правило, если вы используете '%.14f' % lat, вы LOSING PRECISION .

Чтобы получить полную точность из числа с плавающей запятой, используйте repr().

Пример:

>>> lat = 1/3.
>>> lat
0.3333333333333333
>>> str(lat).count('3')
12
>>> ('%.14f' % lat).count('3')
14
>>> repr(lat).count('3')
16
>>>

Кстати, вы используете старый Python.

>>> 0.33245794180134 == 0.33245794180133997
True
>>>

Питоны до 2.7 производят repr(a_float), используя 17 значащих десятичных цифр, потому что это гарантирует, что float(repr(a_float)) == a_float.Новый метод заключается в использовании наименьшего числа цифр, что обеспечит такую ​​же гарантию.Перейдите по этой ссылке и нажмите Ctrl-F для поиска repr().

Если вы получаете эти числа из внешнего источника, то вы можете потерять точность, разместив их и затем сериализовав их14 десятичных цифр точности.

Если вы получаете эти числа вычислением, то вы можете потерять точность, сериализовав их с 14 десятичными цифрами точности.

Резюме: В целом, если вы используете'% .14f'% lat, ВЫ теряют точность - не Python, не арифметика с плавающей точкой, это вы ..

3 голосов
/ 20 апреля 2011

Вы можете попробовать использовать форматирование строки, чтобы получить желаемую точность.

>>> lat = 0.33245794180134
>>> lat
0.33245794180134
>>> "%.14f" % lat
'0.33245794180134'
>>> 

изменить , чтобы включить комментарии:

>>> '{0:.14f}'.format(lat)
'0.33245794180134'
>>> 
2 голосов
/ 20 апреля 2011

str для удобочитаемых представлений.Он редко производит что-то эквивалентное или похожее на выражение, которое выдает ему значение.repr, с другой стороны, явно для этого.Фактически, это то, что REPL использует для обратной связи о результатах выражений.

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

0 голосов
/ 22 апреля 2011

Тип Decimal из десятичного модуля стандартной библиотеки Python - это то, что вам нужно.Он позволяет вам сохранять точность до 28 цифр по умолчанию, но не вводит числа в двоичное представление с плавающей запятой.Тип Decimal также позволяет выполнять математические операции с числами других типов без необходимости преобразования.

Ваш пример преобразован в десятичное число:

>>> import decimal
>>> lat = decimal.Decimal(repr(0.33245794180134))
>>> long = decimal.Decimal(repr(32.57355093956))
>>> lat
Decimal('0.33245794180134')
>>> long
Decimal('32.57355093956')
>>> repr(lat)
'0.33245794180134'
>>> repr(long)
'32.57355093956'

Добавление числа к десятичному числу:

>>> lat + 2
Decimal('2.33245794180134')

Предотвращение неточности двоичных представлений с плавающей запятой чисел, таких как 1.1:

>>> onepointone = decimal.Decimal(repr(1.1))
>>> onepointone
Decimal('1.1')

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

...