Round(), кажется, не округляется должным образом

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

n = 5.59
round(n, 1) # 5.6

Но, на самом деле, вступает полная старая сфера с плавающей запятой, и вы получаете:

5.5999999999999996

Для пользовательского интерфейса мне нужно отобразить 5.6. Я ткнул по Интернету и нашел документацию, что это зависит от моей реализации Python. К сожалению, это происходит как на моей Windows-машине, так и на каждом Linux-сервере, который я пробовал. См. также.

Не удалось создать мою собственную круглую библиотеку, есть ли какой-либо путь вокруг этого?

Ответы

Ответ 1

Я не могу помочь с тем, как он хранится, но по крайней мере форматирование работает правильно:

'%.1f' % round(n, 1) # Gives you '5.6'

Ответ 2

Форматирование работает корректно даже без округления:

"%.1f" % n

Ответ 3

Если вы используете модуль Decimal, вы можете приблизиться без использования функции "round". Вот что я использовал для округления, особенно при написании денежных приложений:

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

Это вернет десятичное число, равное 16.20.

Ответ 4

round(5.59, 1) работает нормально. Проблема состоит в том, что 5.6 невозможно точно представить в двоичной плавающей запятой.

>>> 5.6
5.5999999999999996
>>> 

Как говорит Vinko, вы можете использовать форматирование строк для округления для отображения.

Python имеет модуль для десятичной арифметики, если вам это нужно.

Ответ 5

Вы получаете "5.6", если вы делаете str(round(n, 1)) вместо просто round(n, 1).

Ответ 6

Вы можете переключить тип данных на целое число:

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

А затем отобразите число, вставив десятичный разделитель языка.

Тем не менее, Джимми ответ лучше.

Ответ 7

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

Ответ 8

Посмотрите на десятичный модуль

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

и

Десятичные числа могут быть представлены именно так. В отличие от таких цифр, как 1,1 а на 2.2 нет точного представления в двоичном плавающем точка. Конечные пользователи обычно не будут ожидайте, что 1.1 + 2.2 отобразится 3.3000000000000003, как это происходит с двоичной плавающей запятой.

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

Ответ 9

Это действительно большая проблема. Попробуйте этот код:

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),)

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

Ответ 10

Вы можете использовать оператор формата строки %, аналогичный sprintf.

mystring = "%.2f" % 5.5999

Ответ 11

printf присоска.

print '%.1f' % 5.59  # returns 5.6

Ответ 12

Работает отлично

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

Ответ 13

Я делаю:

int(round( x , 0))

В этом случае мы сначала округляем правильно на уровне единицы, затем преобразуем в целое число, чтобы избежать печати поплавка.

так

>>> int(round(5.59,0))
6

Я думаю, что этот ответ работает лучше, чем форматирование строки, и это также дает мне больше смысла использовать круглую функцию.

Ответ 14

Код:

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

Ответ 15

Здесь, где я вижу, что провал. Что если вы хотите округлить эти 2 числа до одного десятичного знака? 23,45 23,55 Мое образование состояло в том, что от округления этих вы должны получить: 23,4 23,6 "Правило" заключается в том, что вы должны округлять, если предыдущее число было нечетным, а не округлять, если предыдущее число было четным. Функция округления в python просто усекает 5.

Ответ 16

Проблема только в том случае, если последняя цифра 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

Ответ 17

Как насчет:

round(n,1)+epsilon