Arredonde o número para o número inteiro mais próximo


230

Eu tenho tentado arredondar números longos de flutuação como:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Sem sucesso até agora. Eu tentei math.ceil(x), math.floor(x)(apesar de que seria arredondar para cima ou para baixo, o que não é o que estou procurando) e round(x)que não quer trabalhar (ainda flutuar números).

O que eu poderia fazer?

EDIT: CÓDIGO:

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
Eu tentariaint(x)
The Brofessor

isso não daria erro? literal inválido para int () com base 10:
snh_nl 10/10/19

Respostas:


366
int(round(x))

Arredondará e alterará para inteiro

EDITAR:

Você não está atribuindo int (round (h)) a nenhuma variável. Quando você chama int (round (h)), ele retorna o número inteiro, mas não faz mais nada; você precisa alterar essa linha para:

h = int(round(h))

Para atribuir o novo valor a h

EDIT 2:

Como o @plowman disse nos comentários, o Python round()não funciona como seria de se esperar, e isso ocorre porque o modo como o número é armazenado como uma variável geralmente não é o que você vê na tela. Há muitas respostas que explicam esse comportamento:

round () não parece estar arredondando corretamente

Uma maneira de evitar esse problema é usar o decimal, conforme declarado por esta resposta: https://stackoverflow.com/a/15398691/4345659

Para que esta resposta funcione corretamente sem o uso de bibliotecas extras, seria conveniente usar uma função de arredondamento personalizada. Depois de muitas correções, eu vim com a seguinte solução, que, tanto quanto eu testei, evitava todos os problemas de armazenamento. É baseado no uso da representação de string, obtida com repr()(NOT str()!). Parece hacky, mas foi a única maneira que encontrei para resolver todos os casos. Funciona com o Python2 e o 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])

Testes:

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

Finalmente, a resposta corrigida seria:

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

EDIT 3:

Testes:

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

O problema aqui é que o decdécimo-decimal pode ser 9 e, se o dec+1décimo-dígito> = 5, o 9 se tornará um 0 e um 1 deve ser carregado para o dec-1-ésimo dígito.

Se levarmos isso em consideração, obtemos:

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

Na situação descrita acima, b = 10a versão anterior concatenaria ae bresultaria em uma concatenação de 10onde o 0 à direita desapareceria. Esta versão se transforma bna casa decimal correta com base em dec, como um transporte adequado.


2
print ("4.5)", int (round (4.5))) # deu-me 4 print ("5.5)", int (round (5.5))) # deu-me 6
:,

Está relacionado à versão Python. Isso me dá 5 e 6 usando Python 2.7.9 e, como você disse, 4 e 6 usando Python 3.4.2
francisco Sollima

1
Vale a pena notar: esta solução não combina da maneira que você provavelmente espera. Por exemplo, int(round(4.5))rodadas para baixo a 4, enquanto int(round(4.500001))corretamente rodadas a 5.
lavrador

Se você deseja um número inteiro, isso round(x)é suficiente no Python 3.6.2 (e talvez também em versões inferiores). O resultado já é do tipo int. Nota: round(x, n)será do tipo float.
Elmex80s 31/10/19

1
Isso não funciona para 112439.50093565206. Dá o / p -> 11253.0. Maldito estranho .. !!!!
ajin 15/01

24

Use round(x, y). Ele arredondará seu número até a casa decimal desejada.

Por exemplo:

>>> round(32.268907563, 3)
32.269

20

round(value,significantDigit)é a solução comum, no entanto, isso não funciona como seria de esperar da perspectiva matemática quando os valores arredondados terminam em 5. Se o 5dígito estiver logo após o número para o qual você é arredondado, esses valores às vezes são arredondados para cima conforme o esperado (por exemplo, 8.005arredondar para dois dígitos decimais 8.01). Para certos valores devido às peculiaridades da matemática de ponto flutuante, eles são arredondados para baixo!

ie

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

Esquisito.

Supondo que sua intenção seja fazer o arredondamento tradicional para estatísticas nas ciências, este é um invólucro útil para que a roundfunção funcione conforme o esperado, necessitando de importcoisas extras Decimal.

>>> round(0.075,2)

0.07

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

0.08

Aha! Então, com base nisso, podemos fazer uma função ...

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

Basicamente, isso adiciona um valor garantido para ser menor que o dígito menos especificado da string em que você está tentando usar round. Ao adicionar essa pequena quantidade, ele preserva o roundcomportamento da maioria dos casos, enquanto agora assegura se o dígito inferior ao que está sendo arredondado é arredondado para 5cima e, se for 4, arredondado para baixo.

A abordagem do uso 10**(-len(val)-1)foi deliberada, pois é o maior número pequeno que você pode adicionar para forçar a mudança, além de garantir que o valor adicionado nunca mude o arredondamento, mesmo que o decimal .esteja ausente. Eu poderia usar apenas 10**(-len(val))um condicional if (val>1)para subtrair 1mais ... mas é mais simples sempre subtrair o valor, 1pois isso não mudará muito o intervalo aplicável de números decimais que esta solução alternativa pode manipular adequadamente. Essa abordagem falhará se seus valores atingirem os limites do tipo, isso falhará, mas, para quase todo o intervalo de valores decimais válidos, deve funcionar.

Você também pode usar a biblioteca decimal para fazer isso, mas o invólucro que proponho é mais simples e pode ser preferido em alguns casos.


Edit: Obrigado Blckknght por apontar que a 5caixa de franja ocorre apenas para determinados valores. Além disso, uma versão anterior desta resposta não era explícita o suficiente para que o comportamento de arredondamento ímpar ocorresse apenas quando o dígito imediatamente inferior ao dígito para o qual você está arredondando possui a5 .


Não sei por que você acha decimais com 5o último dígito sempre arredondado para baixo. Isso não é o caso em um teste rápido eu fiz com números como 1.5, 2.5, 3.5e assim por diante e 1.05, 1.15, 1.25, 1.35arredondando a uma casa decimal. O primeiro conjunto (metades exatas que arredondam para números inteiros pequenos) sempre arredonda para um número inteiro par. O último conjunto não arredonda consistentemente, provavelmente devido a representações binárias inexatas de alguns dos valores. Os carros alegóricos que têm representações binárias exatas, como o 1.25arredondamento, têm um dígito ainda menos significativo, mas os outros parecem arredondar aleatoriamente.
Blckknght 07/07

Interessante ... você está certo. round(4.0005,3)4.0e round(1.0005,3)1.0, mas round(2.0005,3)2.001e round(3.0005,3)3.001. Mas é exatamente por isso que minha solução proposta é necessária ... você não sabe o que esperar da rodada de ações, nesse caso significativo!
10136 Jason R. Mick

Obrigado por isso. Sua função será útil quando esse problema surgir.
TMWP

1
Você queria ter , digitsno final dessa declaração de retorno? Sem trocadilhos. ( média eu quero dizer)
user3342816 20/0318

Ah, correto, na verdade isso deveria estar lá. Boa captura ... surpreendeu que ninguém mais notou! Poupará aos que utilizam a solução alguma frustração. :-)
Jason R. Mick

15

Para positivos, tente

int(x + 0.5)

Para fazê-lo funcionar também com negativos, tente

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

int()funciona como uma função de piso e, portanto, você pode explorar essa propriedade. Esta é definitivamente a maneira mais rápida.


4
não funciona para negativos>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934

3
Se você se preocupa com caixas de canto, não use a técnica "adicione 0,5 e piso" - há alguns valores que podem não corresponder ao esperado! Consulte stackoverflow.com/a/47302585/2732969 para obter uma captura de C ++ e a stackoverflow.com/a/38744026/2732969 responde nesta mesma pergunta.
Anon

Eu precisava de um método rápido, não precisava ser preciso e não teria muitos casos de canto, e o erro nos casos de canto não é importante no meu cenário. Portanto, este é definitivamente o meu caminho para alguns casos especiais em que a velocidade é prioritária. Não recomende precisão ou exatidão.
AgentM 21/10/19

11

O Python não está fazendo apenas a metade da rodada , como prescrito pelo IEEE 754 ?

Tenha cuidado ao redefinir ou usar arredondamentos "não padrão" ...

(Consulte também https://stackoverflow.com/a/33019948/109839 )


2
Esta resposta é um pouco incerta. Round half to evennão é absolutamente prescrito pelo IEEE 754, mas é apenas uma das várias opções de arredondamento descritas pelo padrão . Round to nearest, ties away from zero(ou seja, o comportamento que a maioria das pessoas espera) também é uma opção e é o padrão, por exemplo, em C / C ++.
tel

Eu concordo, a redação é bastante confusa. O que eu quis dizer com o Python está arredondando a metade para o heven (veja a tabela no final de docs.python.org/3.7/library/… onde roundestá explicado) e está fazendo isso de acordo com o modo como "metade da metade para o par" é prescrito para trabalhar (ou descrito) pela norma.
Mapio 15/05/19

8

Você também pode usar numpy assumindo que, se estiver usando python3.x, aqui está um exemplo

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

7

Sua solução está chamando sem especificar o segundo argumento (número de casas decimais)

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

que é um resultado muito melhor do que

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

Na documentação do Python em https://docs.python.org/3/library/functions.html#round

round (número [, ndigits])

Retornar número arredondado para precisão ndigits após o ponto decimal. Se ndigits for omitido ou for None, ele retornará o número inteiro mais próximo de sua entrada.

Nota

O comportamento de round () para carros alegóricos pode ser surpreendente: por exemplo, round (2.675, 2) fornece 2,67 em vez dos 2,68 esperados. Isso não é um bug: é resultado do fato de que a maioria das frações decimais não pode ser representada exatamente como um float. Consulte Aritmética de ponto flutuante: problemas e limitações para obter mais informações.


1

Se você precisar (por exemplo) de uma aproximação de dois dígitos para A, int(A*100+0.5)/100.0fará o que estiver procurando.

Se você precisar de uma aproximação de três dígitos, multiplique e divida por 1000 e assim por diante.


1

Algo assim também deve funcionar

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

Para esse propósito, sugiro apenas fazer o seguinte -

int(round(x))

Isso lhe dará o número inteiro mais próximo.

Espero que isto ajude!!


0

Eu uso e posso recomendar a seguinte solução (python3.6):

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

Funciona bem para meio-números (positivos e negativos) e funciona ainda mais rápido que int (rodada (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
===========
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.