round() в Python, похоже, не округляется должным образом
документация круглое() функция утверждает, что вы передаете ей число, а позиции после десятичного числа округляются. Таким образом это должны этого:
n = 5.59
round(n, 1) # 5.6
но, на самом деле, старая добрая странность с плавающей точкой вползает, и вы получаете:
5.5999999999999996
для целей пользовательского интерфейса, мне нужно, чтобы отобразить 5.6. Я покопался в интернете и нашел некоторые документация что это зависит от моей реализации Питон. К сожалению, это происходит как на моей машине Windows dev, так и на каждом сервере Linux, который я пробовал. посмотреть здесь.
создать свой собственный круглый библиотеки, есть ли способ обойти это?
17 ответов:
Не могу помочь, как он хранится, но по крайней мере форматирование работает правильно:
'%.1f' % round(n, 1) # gives you '5.6'
Если вы используете десятичный модуль, вы можете приблизиться без использования функции "round". Вот что я использую для округления, особенно при написании денежных приложений:
Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)это вернет десятичное число, которое равно 16.20.
round(5.59, 1)работает нормально. Проблема в том, что 5.6 не может быть представлен точно в двоичной плавающей запятой.>>> 5.6 5.5999999999999996 >>>Как говорит Винко, вы можете использовать форматирование строк для округления для отображения.
Python имеет модуль для десятичной арифметики если вам это нужно.
вы можете переключить тип данных целое число:
>>> n = 5.59 >>> int(n * 10) / 10.0 5.5 >>> int(n * 10 + 0.5) 56а затем отобразить число, вставив десятичный разделитель локали.
однако, Джимми лучше.
математика с плавающей запятой уязвима для небольших, но раздражающих неточностей точности. Если вы можете работать с целым числом или фиксированной точкой, вам будет гарантирована точность.
посмотри модуль десятичных
Decimal " основан на плавающей запятой модель, которая была разработана с людьми в виду, и обязательно имеет главный руководящий принцип – компьютеры должны обеспечивать арифметику это работает так же, как и арифметика, что люди учатся на школа."- выдержка из десятичной дроби арифметическая спецификация.
и
десятичные числа могут быть представленный именно так. В отличие от цифры, как 1.1 а 2.2 не имеют точного представления в двоичном плавающем формате точка. Конечные пользователи обычно не будут ожидайте, что 1.1 + 2.2 будет отображаться как 3.3000000000000003, как это происходит с двоичной плавающей точкой.
Decimal предоставляет вид операций, которые позволяют легко писать приложения, требующие операций с плавающей запятой и и необходимо представить эти результаты в удобочитаемом формате, например, учет.
вы можете использовать оператор строкового формата
%, аналогично sprintf.mystring = "%.2f" % 5.5999
Это действительно большая проблема. Попробуйте этот код:
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),)вы можете видеть истину: точка с плавающей запятой хранится как ближайшая конечная сумма дробей, знаменатели которых являются степенями двух.
Я делаю:
int(round( x , 0))в этом случае мы сначала округляем правильно на уровне единицы, а затем преобразуем в целое число, чтобы избежать печати поплавка.
так
>>> int(round(5.59,0)) 6Я думаю, что этот ответ работает лучше, чем формирование строки, и это также делает более разумным для меня использовать функцию round.
вот где я вижу вокруг, не. Что делать, если вы хотите округлить эти 2 числа до одного десятичного знака? 23.45 23.55 Мое образование состояло в том, что от округления их вы должны получить: 23.4 23.6 "правило" заключается в том, что вы должны округлить, если предыдущее число было нечетным, а не округлить, если предыдущее число было четным. Круглая функция в python просто усекает 5.
код:
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
проблема только тогда, когда последняя цифра 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 {} doesn't 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
Comments