it-swarm.com.ru

Ограничение числа с плавающей запятой до двух десятичных знаков

Я хочу, чтобы a было округлено до 13,95 .

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

Функция round работает не так, как я ожидал.

1392
kevin

Вы сталкиваетесь со старой проблемой с числами с плавающей запятой, что все числа не могут быть представлены. Командная строка просто показывает вам полную форму с плавающей запятой из памяти.

В плавающей точке ваша округленная версия - это то же число. Поскольку компьютеры являются двоичными, они хранят числа с плавающей запятой в виде целого числа, а затем делят его на степень двойки, поэтому 13,95 будет представлено аналогично 125650429603636838/(2 ** 53).

Числа двойной точности имеют точность 53 бита (16 цифр), а обычные числа с плавающей точкой имеют точность 24 бита (8 цифр). с плавающей запятой в Python использует двойную точность для хранения значений.

Например,

  >>> 125650429603636838/(2**53)
  13.949999999999999

  >>> 234042163/(2**24)
  13.949999988079071

  >>> a=13.946
  >>> print(a)
  13.946
  >>> print("%.2f" % a)
  13.95
  >>> round(a,2)
  13.949999999999999
  >>> print("%.2f" % round(a,2))
  13.95
  >>> print("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Если вам нужно только два знака после запятой, как в валюте, у вас есть пара лучших вариантов: 1) Используйте целые числа и сохраняйте значения в центах, а не в долларах, а затем делите на 100, чтобы конвертировать в доллары. 2) Или используйте число с фиксированной точкой, например десятичное число .

1390
Rex Logan

Существуют новые спецификации формата, спецификация формата строки мини-язык :

Вы можете сделать так же, как:

"{0:.2f}".format(13.949999999999999)

Обратите внимание , что выше возвращает строку. Чтобы получить как float, просто оберните с float(...):

float("{0:.2f}".format(13.949999999999999))

Обратите внимание , что перенос с float() ничего не меняет:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
496
Xolve

Встроенная функция round() прекрасно работает в Python 2.7 или более поздней версии.

Пример:

>>> round(14.22222223, 2)
14.22

Проверьте документация .

230
chribsen

Я чувствую, что самый простой подход - использовать функцию format().

Например:

a = 13.949999999999999
format(a, '.2f')

13.95

Это создает число с плавающей точкой в ​​виде строки, округленной до двух десятичных знаков.

132
grant zukowski

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

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

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

89
Roger Pate

Использование

print"{:.2f}".format(a)

вместо

print"{0:.2f}".format(a)

Поскольку последнее может привести к ошибкам вывода при попытке вывести несколько переменных (см. Комментарии).

80
Alexey Antonenko

Попробуйте код ниже:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
69
ax003d

С Python <3 (например, 2.6 или 2.7) есть два способа сделать это.

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

Но обратите внимание, что для Python версий выше 3 (например, 3.2 или 3.3), второй вариант предпочтительно .

Для получения дополнительной информации о втором варианте я предлагаю эту ссылку на форматирование строки из документации Python .

А для получения дополнительной информации по первому варианту этой ссылки будет достаточно и она содержит информацию о различных флагах .

Ссылка: Преобразовать число с плавающей запятой с определенной точностью, а затем скопировать в строку

51
A.J.

Вы можете изменить формат вывода:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
44
Greg Hewgill

TLDR;)

Проблема округления ввода/вывода была окончательно решена с помощью Python 2.7.0 и 3.1 .

Правильно округленное число может быть обратимо преобразовано назад и вперед:
str -> float() -> repr() -> float() ... или Decimal -> float -> str -> Decimal
Десятичный тип больше не требуется для хранения.

(Естественно, может потребоваться округлить результат сложения или вычитания округленных чисел, чтобы исключить накопленные ошибки в последнем бите. Явная десятичная арифметика все еще может быть удобной, но преобразование в строку с помощью str() (то есть с округлением до 12 действительным цифры) обычно достаточно хороши, если не требуется чрезвычайной точности или большого числа последовательных арифметических операций.)

Бесконечный тест :

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Документация

Смотрите Примечания к выпуску Python 2.7 - Другие изменения языка четвертый абзац:

Преобразования между числами с плавающей точкой и строками теперь правильно округлены на большинстве платформ. Эти преобразования происходят во многих разных местах: str () для чисел с плавающей точкой и комплексных чисел; поплавок и сложные конструкторы; числовое форматирование; сериализация и десериализация чисел с плавающей точкой и комплексных чисел с использованием модулей marshal, pickle и json; парсинг чисел с плавающей запятой и мнимых литералов в коде Python; и десятичное преобразование в число с плавающей точкой.

В связи с этим repr () числа с плавающей точкой x теперь возвращает результат, основанный на кратчайшем десятичная строка, которая гарантированно округляется до x при правильном округлении (с режимом округления от половины до четного). Ранее он давал строку, основанную на округлении x до 17 десятичных цифр.

связанный вопрос


Дополнительная информация: Форматирование float перед Python 2.7 было похоже на текущий numpy.float64. Оба типа используют одинаковую 64-битную IEEE 754 двойную точность с 52-битной мантиссой. Большая разница состоит в том, что np.float64.__repr__ часто форматируется с чрезмерным десятичным числом, так что ни один бит не может быть потерян, но между 13.949999999999999 и 13.950000000000001 не существует действительного номера IEEE 754. Результат не Ницца, и преобразование repr(float(number_as_string)) не обратимо с numpy. С другой стороны: float.__repr__ отформатирован так, что важна каждая цифра; последовательность без пробелов и конверсия обратима. Проще говоря: если у вас, возможно, есть номер numpy.float64, преобразуйте его в обычное число с плавающей запятой, чтобы его можно было отформатировать для людей, а не для числовых процессоров, иначе больше ничего не нужно с Python 2.7+.

40
hynekcer

В Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
27
Shashank Singh

Никто здесь, кажется, еще не упомянул об этом, поэтому позвольте мне привести пример в формате Python 3.6 в формате f-string/template-string, который, я думаю, прекрасно выглядит:

>>> f'{a:.2f}'

Это хорошо работает и с более длинными примерами, с операторами и без необходимости использовать парены

>>> print(f'Completed in {time.time() - start:.2f}s')
25
Matt Fletcher

В учебнике Python есть приложение под названием Арифметика с плавающей запятой: проблемы и ограничения. Прочитайте это. Он объясняет, что происходит и почему Python делает все возможное. У него есть даже пример, который соответствует вашему. Позвольте мне процитировать немного:

>>> 0.1
0.10000000000000001

у вас может возникнуть соблазн использовать функцию round(), чтобы вернуться к единственной ожидаемой цифре. Но это не имеет значения:

>>> round(0.1, 1)
0.10000000000000001

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

Другое следствие состоит в том, что, поскольку 0.1 не является точно 1/10, суммирование десяти значений 0.1 может не дать точно 1.0, либо:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

Один из вариантов и решение ваших проблем - использование модуля decimal .

20
nosklo

Вы можете использовать оператор format для округления значения до 2 десятичных знаков в python:

print(format(14.4499923, '.2f')) // output is 14.45
19
Asad Manzoor

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

12
HUAGHAGUAH

Как указал @Matt, Python 3.6 предоставляет f-строки , и они также могут использовать вложенные параметры:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

который будет отображать result: 2.35

11
toto_tico

Для исправления плавающей запятой в динамических типах языков, таких как Python и ​​JavaScript, я использую эту технику

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

Вы также можете использовать десятичное число следующим образом:

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
7
Siamand Maroufi
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14,54

6
MikeL
from decimal import Decimal


def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

Результаты:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
6
weaming

Это просто как 1,2,3:

  1. используйте десятичный модуль для быстрой правильно округленной десятичной арифметики с плавающей запятой:

    д = Десятичный (10000000.0000009)

добиться округления:

   d.quantize(Decimal('0.01'))

будет результат с Decimal('10000000.00')

  1. сделать выше СУХОЙ:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. одобряю этот ответ :)

PS: критика других: форматирование не округляет.

3
Sławomir Lenart

Как насчет лямбда-функции, как это:

arred = lambda x,n : x*(10**n)//1/(10**n)

Таким образом, вы можете просто сделать:

arred(3.141591657,2)

и получить

3.14
2
Gustavo Mirapalheta

Для округления числа до разрешения лучше всего подходит следующий способ, который может работать с любым разрешением (0,01 для двух десятичных знаков или даже для других шагов):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
1
iblasi

Используйте комбинацию десятичного объекта и метода round ().

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
0
Jonathan L