Ответ 1
Я не могу помочь с тем, как он хранится, но по крайней мере форматирование работает правильно:
'%.1f' % round(n, 1) # Gives you '5.6'
В документации для функции round() указано, что вы передаете ей число, а позиции за десятичным знаком округлены. Таким образом, он должен сделать это:
n = 5.59
round(n, 1) # 5.6
Но, на самом деле, вступает полная старая сфера с плавающей запятой, и вы получаете:
5.5999999999999996
Для пользовательского интерфейса мне нужно отобразить 5.6
. Я ткнул по Интернету и нашел документацию, что это зависит от моей реализации Python. К сожалению, это происходит как на моей Windows-машине, так и на каждом Linux-сервере, который я пробовал. См. также.
Не удалось создать мою собственную круглую библиотеку, есть ли какой-либо путь вокруг этого?
Я не могу помочь с тем, как он хранится, но по крайней мере форматирование работает правильно:
'%.1f' % round(n, 1) # Gives you '5.6'
Форматирование работает корректно даже без округления:
"%.1f" % n
Если вы используете модуль Decimal, вы можете приблизиться без использования функции "round". Вот что я использовал для округления, особенно при написании денежных приложений:
Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)
Это вернет десятичное число, равное 16.20.
round(5.59, 1)
работает нормально. Проблема состоит в том, что 5.6 невозможно точно представить в двоичной плавающей запятой.
>>> 5.6
5.5999999999999996
>>>
Как говорит Vinko, вы можете использовать форматирование строк для округления для отображения.
Python имеет модуль для десятичной арифметики, если вам это нужно.
Вы получаете "5.6", если вы делаете str(round(n, 1))
вместо просто round(n, 1)
.
Вы можете переключить тип данных на целое число:
>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56
А затем отобразите число, вставив десятичный разделитель языка.
Тем не менее, Джимми ответ лучше.
Математика с плавающей запятой уязвима для небольших, но раздражающих точных погрешностей. Если вы можете работать с целой или фиксированной точкой, вам будет гарантирована точность.
Посмотрите на десятичный модуль
Десятичная дробь 'основана на плавающей запятой модель, которая была разработана с людьми в виду, и обязательно имеет первостепенный руководящий принцип - компьютеры должны обеспечивать арифметику который работает так же, как арифметика, что люди учатся в школа.' - выдержка из десятичной дроби арифметическая спецификация.
и
Десятичные числа могут быть представлены именно так. В отличие от таких цифр, как 1,1 а на 2.2 нет точного представления в двоичном плавающем точка. Конечные пользователи обычно не будут ожидайте, что 1.1 + 2.2 отобразится 3.3000000000000003, как это происходит с двоичной плавающей запятой.
Десятичное число обеспечивает вид операций, которые облегчают написание приложений, которые требуют операций с плавающей запятой, а также должны представлять эти результаты в удобочитаемом формате, например, для учета.
Это действительно большая проблема. Попробуйте этот код:
print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)
Отображается 4.85. Затем выполните следующие действия:
print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)
и это показывает 4.8. Вы вычисляете вручную точный ответ 4.85, но если вы попробуете:
print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)
вы можете видеть правду: точка с плавающей точкой хранится как ближайшая конечная сумма дробей, знаменатели которой являются степенями двух.
Вы можете использовать оператор формата строки %
, аналогичный sprintf.
mystring = "%.2f" % 5.5999
printf присоска.
print '%.1f' % 5.59 # returns 5.6
Работает отлично
format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round
Я делаю:
int(round( x , 0))
В этом случае мы сначала округляем правильно на уровне единицы, затем преобразуем в целое число, чтобы избежать печати поплавка.
так
>>> int(round(5.59,0))
6
Я думаю, что этот ответ работает лучше, чем форматирование строки, и это также дает мне больше смысла использовать круглую функцию.
Код:
x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1))) # gives you '5.6'
print(float('%.2f' % round(x2,1))) # gives you '5.7'
Выход:
5.6
5.7
Здесь, где я вижу, что провал. Что если вы хотите округлить эти 2 числа до одного десятичного знака? 23,45 23,55 Мое образование состояло в том, что от округления этих вы должны получить: 23,4 23,6 "Правило" заключается в том, что вы должны округлять, если предыдущее число было нечетным, а не округлять, если предыдущее число было четным. Функция округления в python просто усекает 5.
Проблема только в том случае, если последняя цифра 5. Например. 0.045 внутренне сохраняется как 0.044999999999999... Вы можете просто увеличить последнюю цифру до 6 и округлить. Это даст вам желаемый результат.
import re
def custom_round(num, precision=0):
# Get the type of given number
type_num = type(num)
# If the given type is not a valid number type, raise TypeError
if type_num not in [int, float, Decimal]:
raise TypeError("type {} does not define __round__ method".format(type_num.__name__))
# If passed number is int, there is no rounding off.
if type_num == int:
return num
# Convert number to string.
str_num = str(num).lower()
# We will remove negative context from the number and add it back in the end
negative_number = False
if num < 0:
negative_number = True
str_num = str_num[1:]
# If number is in format 1e-12 or 2e+13, we have to convert it to
# to a string in standard decimal notation.
if 'e-' in str_num:
# For 1.23e-7, e_power = 7
e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
# For 1.23e-7, number = 123
number = ''.join(str_num.split('e-')[0].split('.'))
zeros = ''
# Number of zeros = e_power - 1 = 6
for i in range(e_power - 1):
zeros = zeros + '0'
# Scientific notation 1.23e-7 in regular decimal = 0.000000123
str_num = '0.' + zeros + number
if 'e+' in str_num:
# For 1.23e+7, e_power = 7
e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
# For 1.23e+7, number_characteristic = 1
# characteristic is number left of decimal point.
number_characteristic = str_num.split('e+')[0].split('.')[0]
# For 1.23e+7, number_mantissa = 23
# mantissa is number right of decimal point.
number_mantissa = str_num.split('e+')[0].split('.')[1]
# For 1.23e+7, number = 123
number = number_characteristic + number_mantissa
zeros = ''
# Eg: for this condition = 1.23e+7
if e_power >= len(number_mantissa):
# Number of zeros = e_power - mantissa length = 5
for i in range(e_power - len(number_mantissa)):
zeros = zeros + '0'
# Scientific notation 1.23e+7 in regular decimal = 12300000.0
str_num = number + zeros + '.0'
# Eg: for this condition = 1.23e+1
if e_power < len(number_mantissa):
# In this case, we only need to shift the decimal e_power digits to the right
# So we just copy the digits from mantissa to characteristic and then remove
# them from mantissa.
for i in range(e_power):
number_characteristic = number_characteristic + number_mantissa[i]
number_mantissa = number_mantissa[i:]
# Scientific notation 1.23e+1 in regular decimal = 12.3
str_num = number_characteristic + '.' + number_mantissa
# characteristic is number left of decimal point.
characteristic_part = str_num.split('.')[0]
# mantissa is number right of decimal point.
mantissa_part = str_num.split('.')[1]
# If number is supposed to be rounded to whole number,
# check first decimal digit. If more than 5, return
# characteristic + 1 else return characteristic
if precision == 0:
if mantissa_part and int(mantissa_part[0]) >= 5:
return type_num(int(characteristic_part) + 1)
return type_num(characteristic_part)
# Get the precision of the given number.
num_precision = len(mantissa_part)
# Rounding off is done only if number precision is
# greater than requested precision
if num_precision <= precision:
return num
# Replace the last '5' with 6 so that rounding off returns desired results
if str_num[-1] == '5':
str_num = re.sub('5$', '6', str_num)
result = round(type_num(str_num), precision)
# If the number was negative, add negative context back
if negative_number:
result = result * -1
return result
Как насчет:
round(n,1)+epsilon