Круглий номер до найближчого цілого числа


229

Я намагався округлити числа з плаваючою плавкою на кшталт:

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)

3
Я б спробувавint(x)
The Brofessor

це не дасть помилки? недійсний літерал для int () з базою 10:
snh_nl

Відповіді:


366
int(round(x))

Округлить його та змініть на ціле число

Редагувати:

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

h = int(round(h))

Призначити нове значення h

EDIT 2:

Як сказав @plowman в коментарях, Python 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))

EDIT 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 (круглий (4.5))) # дав мені 4 print ("5.5)", int (круглий (5.5))) # дав мені 6:, (
Komm

Це пов'язано з версією 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. Чорт дивно .. !!!!
Аджин

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

Дивно.

Якщо припустити, що ви маєте намір зробити традиційне округлення для статистики в науках, це зручна обгортка, щоб 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()працює як функція підлоги, і тому ви можете використовувати цю властивість. Це, безумовно, найшвидший спосіб.


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 на це саме запитання.
Анон

Мені потрібен був швидкий метод, він не повинен був бути точним і не було б багатьох кутових справ, а помилка в кутових випадках не важлива для мого сценарію. Тож, безумовно, я хочу звернутися до деяких особливих випадків, коли швидкість є пріоритетною. Не рекомендуйте для точності чи точності.
AgentM

11

Чи не просто Python робить круглу половину до рівного , як це передбачено IEEE 754 ?

Будьте ретельно переосмислені або використовуючи "нестандартне" округлення ...

(Дивіться також https://stackoverflow.com/a/33019948/109839 )


2
Ця відповідь трохи незрозуміла. Round half to evenабсолютно не призначено IEEE 754, але натомість є лише одним із декількох варіантів округлення, описаних стандартом . Round to nearest, ties away from zero(тобто поведінка, яку очікують більшість людей) також є варіантом і є типовим для, наприклад, C / C ++.
тел

Я згоден, формулювання досить заплутане. Що я мав на увазі, що Python округляє пів на вісім (див. Таблицю в кінці docs.python.org/3.7/library/… де roundпояснено), і це робиться так, як прописано "кругла половина до рівного" працювати (або описувати) за стандартом.
Mapio

8

Ви також можете використовувати numpy, якщо ви використовуєте python3.x ось приклад

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0

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 пропущено або немає, воно повертає найближче ціле число до його вводу.

Примітка

Поведінка round () для поплавків може бути дивовижною: наприклад, круглий (2.675, 2) дає 2,67 замість очікуваних 2,68. Це не помилка: це результат того, що більшість десяткових дробів не можуть бути представлені точно як плавець. Додаткову інформацію див. У розділі Арифметика з плаваючою комою: питання та обмеження.


1

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

Якщо вам потрібно тризначне наближення, помножте та діліть на 1000 тощо.


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)

0

Для цього я б запропонував зробити лише наступне -

int(round(x))

Це дасть вам найближче ціле число.

Сподіваюся, це допомагає !!


0

Я використовую та можу порадити таке рішення (python3.6):

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

Він чудово працює для пів-чисел (позитивних і негативних) і працює навіть швидше, ніж int (круглий (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
===========
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.