Как исправить неправильные десятичные разряды результата умножения - PullRequest
0 голосов
/ 03 июня 2019

У меня проблема со следующим вычислением:

>>> print(float('32.31') * 1e9)
32310000000.000004

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

>>> print(32.31 * 1e9)
32310000000.000004

Есть ли способ избежать ложного десятичного знака? Анализ строки и округление до числа десятичных знаков не является отложенным решением.

Большое спасибо заранее.

ПРИМЕЧАНИЕ: следующее работает отлично:

>>> print(32.32 * 1e9)
32320000000.0

так что я очень рад, что обнаружил проблему выше во время тестирования.

РЕДАКТИРОВАТЬ: Спасибо за ваши быстрые ответы! Извините, я упустил важный момент. Метод также должен работать, когда результат меньше единицы, например ::1017*

32.31 * 1e-9

... в этом случае я не могу использовать round(32.31 * 1e-9, 1)

Ответы [ 4 ]

2 голосов
/ 03 июня 2019

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

from decimal import Decimal
value = float(Decimal('32.31') * Decimal(1e9))

Это дает желаемое значение,

32310000000.0

Другой способ - использовать модуль fractions, который работает с точными значениями:

from fractions import Fraction
value = float(Fraction('32.31') * Fraction(1e9))

Обратите внимание, что в обоих этих методах мы должны преобразовать 1e9, а не только десятичное значение. Использование 1e9 в качестве числа с плавающей точкой преобразует промежуточные значения в число с плавающей точкой, и снова появляется проблема аппроксимации. В любом из этих способов вы могли бы прекратить окончательное преобразование в тип с плавающей запятой и просто продолжить работу со значением Decimal или Fraction. Любой из этих методов несколько медленнее, чем использование типов с плавающей точкой: вы получаете точность за счет скорости. Это снижение скорости может иметь значение в некоторых ситуациях.


Относительно вашего редактирования вашего вопроса: использование значения 1e-9 в любом из моих методов все равно приведет к тому, что вы хотите, а именно к значению 3.231e-08.

0 голосов
/ 03 июня 2019

Я предполагаю, что вы используете Python 3.

Если вас заботит только результат печати, используйте форматирование строки:

print("{r:1.2f}".format(r=32.31 * 1e9))

Другой способ сделать это - использовать старый синтаксис форматирования:

print("%1.1f" % (32 * 1e9))

Я предпочитаю первый, но любой из них будет работать.

0 голосов
/ 03 июня 2019

Это вызвано ограничением представления двоичной мантиссы поплавков. 32.31 не может быть представлено делением на степень двойки. Если вы знаете, что ваши значения всегда будут целыми числами (или известным числом десятичных знаков), вы можете использовать round() или int(round()), чтобы обойти ограничение.

0 голосов
/ 03 июня 2019

Если вы просто заинтересованы в печати с одним десятичным разрядом, вы можете использовать round, указав число после десятичного разделителя, которое вы хотите иметь, в данном случае 1

print(round(float('32.31') * 1e9, 1))
# 32310000000.0
...