Arrondir le nombre à l'entier le plus proche

230

J'ai essayé d'arrondir de longs nombres flottants comme:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Sans succès jusqu'à présent. J'ai essayé math.ceil(x), math.floor(x)(bien que cela arrondisse vers le haut ou vers le bas, ce qui n'est pas ce que je recherche) et round(x)qui n'a pas fonctionné non plus (toujours des nombres flottants).

"Que pouvais-je faire?"

MODIFIER: CODE:

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
la source
3
J'essaieraisint(x)
The Brofessor
cela ne donnerait-il pas une erreur? littéral invalide pour int () avec base 10:
snh_nl

Réponses:

366
int(round(x))

Va l'arrondir et le changer en entier

ÉDITER:

Vous n'affectez int (round (h)) à aucune variable. Lorsque vous appelez int (round (h)), il renvoie le nombre entier mais ne fait rien d'autre; vous devez changer cette ligne pour:

h = int(round(h))

Pour affecter la nouvelle valeur à h

EDIT 2:

Comme @plowman l'a dit dans les commentaires, Python round()ne fonctionne pas comme on pourrait s'y attendre normalement, et c'est parce que la façon dont le nombre est stocké sous forme de variable n'est généralement pas la façon dont vous le voyez à l'écran. Il existe de nombreuses réponses qui expliquent ce comportement:

round () ne semble pas arrondir correctement

Une façon d'éviter ce problème est d'utiliser la décimale comme indiqué par cette réponse: https://stackoverflow.com/a/15398691/4345659

Pour que cette réponse fonctionne correctement sans utiliser de bibliothèques supplémentaires, il serait pratique d'utiliser une fonction d'arrondi personnalisée. Après beaucoup de corrections, j'ai trouvé la solution suivante, qui autant que j'ai testé a évité tous les problèmes de stockage. Il est basé sur l'utilisation de la représentation sous forme de chaîne, obtenue avec repr()(NOT str()!). Cela a l'air hacky mais c'était la seule façon que j'ai trouvée pour résoudre tous les cas. Il fonctionne avec Python2 et 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])

Tests:

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

Enfin, la réponse corrigée serait:

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

EDIT 3:

Tests:

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

Le problème ici est que la dec-ème décimale peut être 9 et si le dec+1-ème chiffre> = 5, le 9 deviendra un 0 et un 1 devrait être porté au dec-1-ème chiffre.

Si nous prenons cela en considération, nous obtenons:

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

Dans la situation décrite ci-dessus b = 10et la version précédente ne ferait que concaténer aet bce qui entraînerait une concaténation de l' 10endroit où le 0 de fin disparaîtrait. Cette version se transforme bà la bonne décimale en fonction dec, comme un report approprié.

francisco sollima
la source
2
print ("4.5)", int (round (4.5))) # m'a donné 4 print ("5.5)", int (round (5.5))) # m'a donné 6
:,
C'est lié à la version Python. Cela me donne 5 et 6 en utilisant Python 2.7.9 et, comme vous l'avez dit, 4 et 6 en utilisant Python 3.4.2
francisco sollima
1
À noter: cette solution ne se déroule pas comme vous vous y attendez probablement. Par exemple, int(round(4.5))arrondit à 4 tout en int(round(4.500001))arrondissant correctement à 5.
laboureur
Si vous voulez un entier, cela round(x)suffit dans Python 3.6.2 (et peut-être aussi dans les versions inférieures). Le résultat est déjà de type int. Remarque: round(x, n)sera de type float.
Elmex80s
1
Cela ne fonctionne pas pour 112439.50093565206. Il donne o / p -> 11253.0. Merde bizarre .. !!!!
AJIN
24

Utilisez round(x, y). Il arrondira votre nombre à la décimale souhaitée.

Par exemple:

>>> round(32.268907563, 3)
32.269
Satyaki Sanyal
la source
20

round(value,significantDigit)est la solution ordinaire, mais cela ne fonctionne pas comme on pourrait s'y attendre d'un point de vue mathématique lorsque les valeurs arrondies se terminent par 5. Si le 5est dans le chiffre juste après celui auquel vous êtes arrondi, ces valeurs ne sont parfois arrondies que prévu (c'est- 8.005à- dire que l' arrondi à deux chiffres décimaux donne 8.01). Pour certaines valeurs dues aux bizarreries des mathématiques en virgule flottante, elles sont arrondies à la place!

c'est à dire

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

Bizarre.

En supposant que votre intention est de faire l'arrondi traditionnel pour les statistiques dans les sciences, c'est un wrapper pratique pour faire roundfonctionner la fonction comme prévu, en ayant besoin de importchoses supplémentaires comme Decimal.

>>> round(0.075,2)

0.07

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

0.08

Ah! Donc, sur cette base, nous pouvons faire une fonction ...

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

Fondamentalement, cela ajoute une valeur garantie d'être inférieure au chiffre le moins donné de la chaîne sur laquelle vous essayez d'utiliser round. En ajoutant cette petite quantité, il préserve le roundcomportement de dans la plupart des cas, tout en s'assurant maintenant que si le chiffre inférieur à celui qui est arrondi est arrondi 5, et s'il l'est, 4il arrondit vers le bas.

L'approche de l'utilisation a 10**(-len(val)-1)été délibérée, car il s'agit du plus petit nombre que vous pouvez ajouter pour forcer le décalage, tout en garantissant que la valeur que vous ajoutez ne change jamais l'arrondi même si la décimale .est manquante. Je pourrais utiliser juste 10**(-len(val))avec une conditionnelle if (val>1)pour soustraire 1plus ... mais il est plus simple de toujours soustraire 1car cela ne changera pas beaucoup la plage de nombres décimaux applicable que cette solution de contournement peut gérer correctement. Cette approche échouera si vos valeurs atteignent les limites du type, cela échouera, mais pour presque toute la plage de valeurs décimales valides, cela devrait fonctionner.

Vous pouvez également utiliser la bibliothèque décimale pour accomplir cela, mais le wrapper que je propose est plus simple et peut être préféré dans certains cas.


Edit: Merci Blckknght d' avoir souligné que le 5cas de frange ne se produit que pour certaines valeurs. De plus, une version antérieure de cette réponse n'était pas suffisamment explicite pour que le comportement d'arrondi impair se produise uniquement lorsque le chiffre immédiatement inférieur au chiffre auquel vous arrondissez a un5 .

Jason R. Mick
la source
Je ne sais pas pourquoi vous pensez que les décimales avec 5comme dernier chiffre arrondiront toujours vers le bas. Ce n'est pas le cas dans un test rapide , je viens de le faire avec des chiffres comme 1.5, 2.5, 3.5et ainsi de suite et 1.05, 1.15, 1.25, 1.35arrondi à la première décimale. Le premier ensemble (arrondi par moitié exact à de petits entiers) est toujours arrondi à un entier pair. Ce dernier ensemble ne s'arrondit pas de manière cohérente, probablement en raison de représentations binaires inexactes de certaines valeurs. Les flotteurs qui ont des représentations binaires exactes comme 1.25round ont un chiffre encore moins significatif, mais les autres semblent arrondir de manière aléatoire.
Blckknght
Intéressant ... vous avez raison. round(4.0005,3)donne 4.0et round(1.0005,3)donne 1.0, mais round(2.0005,3)donne 2.001et round(3.0005,3)donne 3.001. Mais c'est précisément la raison pour laquelle la solution que je propose est nécessaire ... vous ne savez pas à quoi vous attendre du stock stock, sur ce cas significatif!
Jason R. Mick
Merci pour cela. Votre fonction vous sera utile lorsque ce problème surviendra.
TMWP
1
Vouliez-vous avoir , digitsà la fin de cette déclaration de retour? Sans jeu de mots. ( Moyenne que je veux dire)
user3342816
Ah, c'est vrai, cela aurait dû être là. Bonne prise ... surpris que personne d'autre n'ait remarqué! Sauvera ceux qui utilisent la solution une certaine frustration. :-)
Jason R. Mick
15

Pour les points positifs, essayez

int(x + 0.5)

Pour que cela fonctionne aussi pour les négatifs, essayez

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

int()fonctionne comme une fonction de plancher et vous pouvez donc exploiter cette propriété. C'est certainement le moyen le plus rapide.

Embrouiller
la source
4
ne fonctionne pas pour les négatifs>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934
3
Si vous vous souciez des caisses d'angle, n'utilisez pas la technique "ajouter 0,5 et le sol" - il existe des valeurs qui peuvent ne pas correspondre à ce que vous attendez! Voir stackoverflow.com/a/47302585/2732969 pour une prise C ++ et la réponse stackoverflow.com/a/38744026/2732969 dans cette même question.
Anon
J'avais besoin d'une méthode rapide, elle n'avait pas besoin d'être précise et n'aurait pas beaucoup de cas d'angle, et l'erreur dans les cas d'angle n'est pas importante dans mon scénario. C'est donc définitivement mon choix pour certains cas spéciaux où la vitesse est prioritaire. Ne recommande pas pour la précision ou l'exactitude.
AgentM
11

N'est-ce pas seulement Python qui fait la moitié du tour pour égaliser , comme prescrit par IEEE 754 ?

Soyez prudent en redéfinissant ou en utilisant l'arrondi "non standard" ...

(Voir aussi https://stackoverflow.com/a/33019948/109839 )

Mapio
la source
2
Cette réponse n'est pas claire. Round half to evenn'est absolument pas prescrit par IEEE 754, mais n'est à la place qu'une des nombreuses options d'arrondi décrites par la norme . Round to nearest, ties away from zero(c'est-à-dire le comportement que la plupart des gens attendent) est également une option, et est la valeur par défaut, par exemple, en C / C ++.
tél
Je suis d'accord, le libellé est assez déroutant. Ce que je voulais dire, c'est que Python arrondit la moitié à heven (voir le tableau à la fin de docs.python.org/3.7/library/… où il roundest expliqué) et il le fait selon la façon dont "arrondir la moitié à égal" est prescrit de travailler (ou décrit) par la norme.
Mapio
8

Vous pouvez également utiliser numpy en supposant que si vous utilisez python3.x voici un exemple

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
sushmit
la source
7

Votre solution appelle round sans spécifier le deuxième argument (nombre de décimales)

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

ce qui est un bien meilleur résultat que

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

À partir de la documentation Python sur https://docs.python.org/3/library/functions.html#round

rond (nombre [, ndigits])

Renvoie le nombre arrondi à la précision de ndigits après le point décimal. Si ndigits est omis ou vaut None, il renvoie l'entier le plus proche à son entrée.

Remarque

Le comportement de round () pour les flottants peut être surprenant: par exemple, round (2.675, 2) donne 2,67 au lieu de 2,68 attendu. Ce n'est pas un bug: c'est le résultat du fait que la plupart des fractions décimales ne peuvent pas être représentées exactement comme un flottant. Voir Arithmétique en virgule flottante: problèmes et limites pour plus d'informations.

Geai
la source
1

Si vous avez besoin (par exemple) d'une approximation à deux chiffres pour A, alors vous int(A*100+0.5)/100.0ferez ce que vous cherchez.

Si vous avez besoin d'une approximation à trois chiffres, multipliez et divisez par 1000, etc.

Hoo
la source
1

Quelque chose comme ça devrait aussi fonctionner

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
la source
0

À cette fin, je suggérerais simplement de faire la chose suivante -

int(round(x))

Cela vous donnera l'entier le plus proche.

J'espère que cela t'aides!!

rahul ranjan
la source
0

J'utilise et je peux conseiller la solution suivante (python3.6):

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

Il fonctionne très bien pour les demi-nombres (positifs et négatifs) et fonctionne encore plus rapidement que 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
===========
Василий Прядченко
la source