Округлить число до ближайшего целого

230

Я пытался округлить длинные числа типа:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Пока безуспешно. Я попытался math.ceil(x), math.floor(x)(хотя это округло бы вверх или вниз, что не то, что я ищу), и round(x)которое также не работало (все еще числа с плавающей запятой).

Что я мог сделать?

РЕДАКТИРОВАТЬ: КОД:

for i in widthRange:
    for j in heightRange:
        r, g, b = rgb_im.getpixel((i, j))
        h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
        h = h * 360
        int(round(h))
        print(h)
vandernath
источник
3
Я бы попробовалint(x)
Брофессор
это не даст ошибку? недопустимый литерал для int () с основанием 10:
snh_nl

Ответы:

366
int(round(x))

Округлит его и изменит его на целое

РЕДАКТИРОВАТЬ:

Вы не присваиваете int (round (h)) какой-либо переменной. Когда вы вызываете int (round (h)), он возвращает целое число, но больше ничего не делает; Вы должны изменить эту строку для:

h = int(round(h))

Чтобы присвоить новое значение h

РЕДАКТИРОВАТЬ 2:

Как сказал @plowman в комментариях, Python round() не работает так, как обычно ожидают, и это потому, что способ хранения числа в качестве переменной обычно не тот, который вы видите на экране. Есть много ответов, объясняющих это поведение:

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

Один из способов избежать этой проблемы - использовать десятичное число, как указано в этом ответе: https://stackoverflow.com/a/15398691/4345659

Для правильной работы этого ответа без использования дополнительных библиотек было бы удобно использовать пользовательскую функцию округления. После многих исправлений я пришел к следующему решению, которое, насколько я тестировал, позволило избежать всех проблем с хранением. Он основан на использовании строкового представления, полученного с помощью repr()(НЕ str()!). Это выглядит неприлично, но это был единственный способ, который я нашел, чтобы решить все дела. Работает как с Python2, так и с Python3.

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
        return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
    return float(num[:-1])

тесты:

>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>> 
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0

Наконец, исправленный ответ будет следующим:

# Having proper_round defined as previously stated
h = int(proper_round(h))

РЕДАКТИРОВАТЬ 3:

тесты:

>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1  # should be 7

Здесь есть то, что decдесятая dec+1цифра может быть 9, а если десятая цифра> = 5, то 9 станет 0, а 1 должна быть перенесена в dec-1третью цифру.

Если мы примем это во внимание, мы получим:

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
      a = num[:-2-(not dec)]       # integer part
      b = int(num[-2-(not dec)])+1 # decimal part
      return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
    return float(num[:-1])

В описанной выше ситуации b = 10и предыдущей версией бы просто конкатенации , aи bчто привело бы к конкатенации , 10где задн 0 исчезнет. Эта версия преобразуется bв правильное десятичное место на основе dec, как правильный перенос.

Франсиско Соллима
источник
2
print ("4.5)", int (round (4.5))) # дал мне 4 print ("5.5)", int (round (5.5))) # дал мне 6:, (
Комм
Это связано с версией Python. Это дает мне 5 и 6 с использованием Python 2.7.9 и, как вы сказали, 4 и 6 с использованием Python 3.4.2
francisco sollima
1
Стоит отметить: это решение не округляется так, как вы, вероятно, ожидаете. Например, int(round(4.5))округляется до 4 , а int(round(4.500001))правильно округляется до 5.
пахарь
Если вам нужно целое число, тогда round(x)достаточно в Python 3.6.2 (и, возможно, также в более низких версиях). Результат уже имеет тип int. Примечание: round(x, n)будет иметь тип float.
Elmex80s
1
Это не работает для 112439.50093565206. Это дает о / п -> 11253,0. Чертовски странно .. !!!!
Ajin
24

использование round(x, y) . Он будет округлять ваш номер до желаемого десятичного знака.

Например:

>>> round(32.268907563, 3)
32.269
Сатьяки Саньял
источник
20

round(value,significantDigit)это обычное решение, однако это не работает так, как можно было бы ожидать с математической точки зрения, когда значения округляются до 5. Если значение 5находится в цифре сразу после того, к которому вы округлили, эти значения только иногда округляются, как ожидалось (т.е. 8.005округление до двух десятичных цифр дает8.01 ). Для определенных значений из-за особенностей математики с плавающей запятой они округляются вместо этого!

т.е.

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

Weird.

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

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*5),2)

0.08

Ага! На основании этого мы можем сделать функцию ...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

По сути, это добавляет значение, которое гарантированно будет меньше, чем наименее заданная цифра строки, на которой вы пытаетесь использовать round. Добавляя это небольшое количество, оно roundв большинстве случаев сохраняет поведение, в то же время теперь проверяя, округляет ли цифра меньше, чем округляемая, 5и округляет ли она4 .

Подход использования 10**(-len(val)-1)был преднамеренным, так как это наибольшее небольшое число, которое вы можете добавить, чтобы форсировать сдвиг, при этом гарантируя, что добавляемое вами значение никогда не изменит округление, даже если десятичное число. отсутствует. Я мог бы использовать только 10**(-len(val))с условным условием, if (val>1)чтобы вычесть 1больше ... но проще всегда всегда вычитать, 1поскольку это не сильно изменит применимый диапазон десятичных чисел, который этот обходной путь может правильно обработать. Этот подход потерпит неудачу, если ваши значения достигнут пределов типа, это не удастся, но почти для всего диапазона допустимых десятичных значений это должно работать.

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


Изменить: Спасибо Blckknght за указание, что 5крайний случай происходит только для определенных значений. Также более ранняя версия этого ответа не была достаточно явной, так что странное поведение округления происходит только тогда, когда цифра, непосредственно уступающая цифре, к которой вы округляете, имеет5 .

Джейсон Р. Мик
источник
Я не уверен, почему вы думаете, что десятичные дроби с 5последней цифрой всегда будут округляться. Это не тот случай в быстром тесте я просто с числами , как 1.5, 2.5, 3.5и так далее , и 1.05, 1.15, 1.25, 1.35округление до одного знака после запятой. Первый набор (точные половинки округляются до маленьких целых) всегда округляется до четного целого числа. Последний набор не округляется последовательно, вероятно, из-за неточных двоичных представлений некоторых значений. Поплавки, которые имеют точные двоичные представления, такие как 1.25округление, имеют даже наименее значащую цифру, но остальные, кажется, округляются случайным образом.
Blckknght
Интересно ... ты прав. round(4.0005,3)дает 4.0и round(1.0005,3)дает 1.0, но round(2.0005,3)дает 2.001и round(3.0005,3)дает 3.001. Но именно поэтому мое предложенное решение необходимо ... вы не знаете, чего ожидать от раунда акций, в этом важном случае!
Джейсон Р. Мик
Спасибо за это. Ваша функция пригодится, когда возникнет эта проблема.
TMWP
1
Вы хотели иметь , digitsв конце этого оператора возврата? Не каламбур предназначен. ( Средний я имею в виду)
user3342816
Ах, правильно, действительно, это должно было быть там. Хороший улов ... удивил, что никто не заметил! Спасет тех, кто использует решение, некоторое разочарование. :-)
Джейсон Р. Мик
15

Для позитива попробуйте

int(x + 0.5)

Чтобы это работало и на негативы, попробуйте

int(x + (0.5 if x > 0 else -0.5))

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

Confuse
источник
4
не работает для негативов>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934
3
Если вам небезразличны угловые случаи, не используйте технику «добавить 0,5 и пол» - некоторые значения могут отличаться от ожидаемых! См. Stackoverflow.com/a/47302585/2732969 для получения информации о C ++ и ответа на stackoverflow.com/a/38744026/2732969 в этом же вопросе.
Anon
Мне нужен был быстрый метод, он не должен быть точным и не будет иметь много угловых случаев, и ошибка в угловых случаях не важна в моем сценарии. Так что это определенно мой путь для некоторых особых случаев, где скорость является приоритетом. Не рекомендую для точности или точности.
AgentM
11

Разве Python не выполняет круглый раунд , как это предписано IEEE 754 ?

Будьте осторожны, переопределяя или используя «нестандартные» округления ...

(См. Также https://stackoverflow.com/a/33019948/109839 )

Mapio
источник
2
Этот ответ немного неясен. Round half to evenабсолютно не предписывается IEEE 754, но вместо этого является лишь одним из нескольких вариантов округления, описанных в стандарте . Round to nearest, ties away from zero(то есть поведение, ожидаемое большинством людей) также является опцией и используется по умолчанию, например, в C / C ++.
Тел
Я согласен, формулировка довольно запутанная. То, что я имел в виду, что Python округляет половину до heven (см. Таблицу в конце docs.python.org/3.7/library/… где roundобъясняется) и делает это в соответствии со способом, предписанным «округлить с половины до четного» работать (или описывать) по стандарту.
Мапио
8

Вы также можете использовать numpy, если вы используете python3.x, вот пример

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
sushmit
источник
7

Ваше решение обзванивает без указания второго аргумента (количество десятичных знаков)

>>> round(0.44)
0
>>> round(0.64)
1

что намного лучший результат, чем

>>> int(round(0.44, 2))
0
>>> int(round(0.64, 2))
0

Из документации Python по адресу https://docs.python.org/3/library/functions.html#round

раунд (число [, ndigits])

Возвращаемое число, округленное до ndigits точности после десятичной точки. Если ndigits опущен или равен None, он возвращает ближайшее целое число на свой вход.

Заметка

Поведение round () для чисел с плавающей точкой может быть удивительным: например, round (2.675, 2) дает 2.67 вместо ожидаемых 2.68. Это не ошибка: это результат того факта, что большинство десятичных дробей не может быть представлено в точности как число с плавающей точкой. Посмотрите Арифметику с плавающей запятой: Проблемы и Ограничения для получения дополнительной информации.

сойка
источник
1

Если вам нужно (например) двухзначное приближение для A, то int(A*100+0.5)/100.0 будете делать то, что ищете.

Если вам нужно трехзначное приближение, умножьте и разделите на 1000 и так далее.

Hoo
источник
1

Нечто подобное должно также работать

import numpy as np    

def proper_round(a):
    '''
    given any real number 'a' returns an integer closest to 'a'
    '''
    a_ceil = np.ceil(a)
    a_floor = np.floor(a)
    if np.abs(a_ceil - a) < np.abs(a_floor - a):
        return int(a_ceil)
    else:
        return int(a_floor)
Aabhaas
источник
0

Для этого я бы предложил сделать следующее:

int(round(x))

Это даст вам ближайшее целое число.

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

Рахул Ранджан
источник
0

Я использую и могу посоветовать следующее решение (python3.6):

y = int(x + (x % (1 if x >= 0 else -1)))

Он отлично работает для половинных чисел (положительных и отрицательных) и работает даже быстрее, чем int (round (x)):

round_methods = [lambda x: int(round(x)), 
                 lambda x: int(x + (x % (1 if x >= 0 else -1))),
                 lambda x: np.rint(x).astype(int),
                 lambda x: int(proper_round(x))]

for rm in round_methods:
    %timeit rm(112.5)
Out:
201 ns ± 3.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
159 ns ± 0.646 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
925 ns ± 7.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.18 µs ± 8.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

for rm in round_methods:
    print(rm(112.4), rm(112.5), rm(112.6))
    print(rm(-12.4), rm(-12.5), rm(-12.6))
    print('=' * 11)

Out:
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
Василий Прядченко
источник