Ограничение поплавков на две десятичные точки

Я хочу, чтобы a округлялся до 13.95.

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

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

1345
18 янв. '09 в 21:16
источник поделиться
23 ответов

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

В плавающей запятой ваша округленная версия имеет одинаковое число. Поскольку компьютеры являются двоичными, они сохраняют числа с плавающей запятой как целое число, а затем делят его на две силы, поэтому 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) Или используйте номер фиксированной точки, такой как десятичный.

1355
18 янв. '09 в 21:23
источник

Связанные вопросы


Похожие вопросы

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

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

"{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
490
30 июня '11 в 21:53
источник

Встроенный round() работает отлично в Python 2.7 или новее.

Пример:

>>> round(14.22222223, 2)
14.22

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

218
31 дек. '17 в 13:51
источник

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

Например:

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

13.95

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

130
26 янв. '15 в 1:26
источник

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

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

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

89
18 янв. '09 в 21:40
источник

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

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

вместо

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

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

74
04 авг. '17 в 11:40
источник

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

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
69
26 авг. '13 в 9:46
источник

С 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.

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

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

51
11 дек. '13 в 9:37
источник

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

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
43
18 янв. '09 в 21:31
источник

TL;DR;)

Проблема округления ввода/вывода была окончательно решена с помощью 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; парсинг float и мнимых литералов в коде 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+.

37
31 янв. '16 в 21:33
источник

В Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
27
16 марта '18 в 13:49
источник

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

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

Он хорошо работает и с более длинными примерами, с операторами и не нуждающимися в parens:

>>> print(f'Completed in {time.time() - start:.2f}s')
22
12 дек. '17 в 17:45
источник

В учебнике 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
19 янв. '09 в 5:05
источник

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

print(format(14.4499923, '.2f')) // output is 14.45
12
06 февр. '19 в 9:37
источник

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

12
18 янв. '09 в 21:33
источник

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

value = 2.34558
precision = 2
width = 4

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

который отобразит result: 2.35

11
01 февр. '18 в 12:43
источник

Для исправления плавающей запятой в динамических языках типа 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

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

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
02 апр. '14 в 23:08
источник
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
21 дек. '18 в 10:55
источник
orig_float = 232569 / 16000.0

14.5355625

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

14.54

6
04 сент. '17 в 15:38
источник

Это просто как 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))

ИЛИ ЖЕ

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

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

3
29 янв. '19 в 20:43
источник

Чтобы округлить число до разрешения, наилучшим способом является следующий, который может работать с любым разрешением (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
26 авг. '15 в 12:17
источник

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

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

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

arred(3.141591657,2)

и получить

3.14
0
28 апр. '19 в 3:45
источник

Метод, который я использую, - это метод нарезания строк. Это относительно быстро и просто.

Сначала преобразуем float в строку, выберите нужную длину.

float = str(float)[:5]

В одной строке выше мы преобразовали значение в строку, а затем сохранили строку только до ее первых четырех цифр или символов (включительно).

Надеюсь, что это поможет!

-13
31 дек. '16 в 11:05
источник

Посмотрите другие вопросы по меткам или Задайте вопрос