Arrondir à 5 (ou autre nombre) en Python


162

Existe-t-il une fonction intégrée qui peut arrondir comme suit?

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20

Réponses:


304

Je ne connais pas de fonction standard en Python, mais cela fonctionne pour moi:

Python 2

def myround(x, base=5):
    return int(base * round(float(x)/base))

Python3

def myround(x, base=5):
    return base * round(x/base)

Il est facile de voir pourquoi ce qui précède fonctionne. Vous voulez vous assurer que votre nombre divisé par 5 est un entier correctement arrondi. Donc, nous faisons d'abord exactement cela ( round(float(x)/5)floatc'est seulement nécessaire dans Python2), puis puisque nous avons divisé par 5, nous multiplions également par 5. La conversion finale en intest parce que round()renvoie une valeur à virgule flottante dans Python 2.

J'ai rendu la fonction plus générique en lui donnant un baseparamètre, par défaut à 5.


3
Si seulement des entiers et des arrondis vers le bas, vous pouvez aussi simplement fairex // base * base
Tjorriemorrie

7
c'est moi qui suis paranoïaque mais je préfère utiliser floor()et ceil()plutôt que lancer:base * floor(x/base)
user666412

1
@ user666412 math.flooret math.ceiln'autorise pas l'utilisation avec une base personnalisée, donc la préférence n'est pas pertinente.
Acumenus

48

Pour arrondir à des valeurs non entières, telles que 0,05:

def myround(x, prec=2, base=.05):
  return round(base * round(float(x)/base),prec)

J'ai trouvé cela utile car je pouvais simplement faire une recherche et remplacer dans mon code pour changer "round (" en "myround (", sans avoir à changer les valeurs des paramètres.


2
Vous pouvez utiliser: def my_round(x, prec=2, base=0.05): return (base * (np.array(x) / base).round()).round(prec) qui accepte également les tableaux numpy.
saubhik

23

C'est juste une question de mise à l'échelle

>>> a=[10,11,12,13,14,15,16,17,18,19,20]
>>> for b in a:
...     int(round(b/5.0)*5.0)
... 
10
10
10
15
15
15
15
15
20
20
20

14

Supprimer le «reste» fonctionnerait:

rounded = int(val) - int(val) % 5

Si la valeur est déjà un entier:

rounded = val - val % 5

En tant que fonction:

def roundint(value, base=5):
    return int(value) - int(value) % int(base)

J'aime cette réponse pour arrondir à la valeur fractionnaire la plus proche. c'est-à-dire si je veux seulement des incréments de 0,25.
jersey bean


9

round (x [, n]): les valeurs sont arrondies au multiple de 10 le plus proche de la puissance moins n. Donc si n est négatif ...

def round5(x):
    return int(round(x*2, -1)) / 2

Puisque 10 = 5 * 2, vous pouvez utiliser la division entière et la multiplication avec 2, plutôt que la division flottante et la multiplication avec 5,0. Pas que cela compte beaucoup, à moins que vous n'aimiez un peu changer

def round5(x):
    return int(round(x << 1, -1)) >> 1

1
+1 pour nous montrer que round () peut gérer l'arrondi à des multiples autres que 1.0, y compris des valeurs plus élevées. (Notez, cependant, que l'approche de transfert de bits ne fonctionnera pas avec les flottants, sans parler qu'elle est beaucoup moins lisible pour la plupart des programmeurs.)
Peter Hansen

1
@Peter Hansen merci pour le +1. Besoin d'avoir un int (x) pour que le transfert de bits fonctionne avec des flottants. D'accord, ce n'est pas le plus lisible et je ne l'utiliserais pas moi-même, mais j'ai aimé la "pureté" de celui-ci n'impliquant que des 1 et non des 2 ou des 5.
pwdyson

6

Désolé, je voulais commenter la réponse d'Alok Singhai, mais cela ne me le permettra pas en raison d'un manque de réputation = /

Quoi qu'il en soit, nous pouvons généraliser une étape de plus et aller:

def myround(x, base=5):
    return base * round(float(x) / base)

Cela nous permet d'utiliser des bases non entières, comme .25ou toute autre base fractionnaire.


N'essayez pas de contourner les nouvelles restrictions utilisateur en publiant un commentaire comme réponse. Les restrictions existent pour une raison . Tenez-en compte comme une raison possible pour savoir pourquoi et comment certaines réponses sont-elles supprimées?
Au revoir StackExchange

4

Version modifiée de divround :-)

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step

donc dans ce cas, vous utilisez divround (valeur, 5, 3)? ou peut-être divround (valeur, 5, 2,5)?
pwdyson

divround (valeur, 5, 3), exactement.
Christian Hausknecht

4

Utilisation:

>>> def round_to_nearest(n, m):
        r = n % m
        return n + m - r if r + r >= m else n - r

Il n'utilise pas de multiplication et ne convertira pas de / en flottants.

Arrondir au multiple de 10 le plus proche:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 10)))
-21  =>  -20
-18  =>  -20
-15  =>  -10
-12  =>  -10
 -9  =>  -10
 -6  =>  -10
 -3  =>    0
  0  =>    0
  3  =>    0
  6  =>   10
  9  =>   10
 12  =>   10
 15  =>   20
 18  =>   20
 21  =>   20
 24  =>   20
 27  =>   30

Comme vous pouvez le voir, cela fonctionne pour les nombres négatifs et positifs. Les égalités (par exemple -15 et 15) seront toujours arrondies vers le haut.

Un exemple similaire arrondi au multiple de 5 le plus proche, démontrant qu'il se comporte également comme prévu pour une "base" différente:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 5)))
-21  =>  -20
-18  =>  -20
-15  =>  -15
-12  =>  -10
 -9  =>  -10
 -6  =>   -5
 -3  =>   -5
  0  =>    0
  3  =>    5
  6  =>    5
  9  =>   10
 12  =>   10
 15  =>   15
 18  =>   20
 21  =>   20
 24  =>   25
 27  =>   25

2

Si quelqu'un a besoin d'un «arrondi financier» (0,5 arrondi toujours supérieur):

def myround(x, base=5):
    roundcontext = decimal.Context(rounding=decimal.ROUND_HALF_UP)
    decimal.setcontext(roundcontext)
    return int(base *float(decimal.Decimal(x/base).quantize(decimal.Decimal('0'))))

Selon la documentation, les autres options d'arrondi sont:

ROUND_CEILING (vers Infinity),
ROUND_DOWN (vers zéro),
ROUND_FLOOR (vers -Infinity),
ROUND_HALF_DOWN (au plus proche avec des liens allant vers zéro),
ROUND_HALF_EVEN (au plus proche avec des liens allant au plus proche entier pair),
ROUND_HALF_UP (au plus proche avec des liens allant loin de zéro), ou
ROUND_UP (loin de zéro).
ROUND_05UP (loin de zéro si le dernier chiffre après arrondi vers zéro aurait été 0 ou 5; sinon vers zéro)

Par défaut, Python utilise ROUND_HALF_EVEN car il présente certains avantages statistiques (les résultats arrondis ne sont pas biaisés).


2

Pour les entiers et avec Python 3:

def divround_down(value, step):
    return value//step*step


def divround_up(value, step):
    return (value+step-1)//step*step

Produire:

>>> [divround_down(x,5) for x in range(20)]
[0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15]
>>> [divround_up(x,5) for x in range(20)]
[0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 20, 20, 20, 20]


1

Multiple suivant de 5

Considérez que 51 doit être converti en 55:

code here

mark = 51;
r = 100 - mark;
a = r%5;
new_mark = mark + a;

1

Voici mon code C. Si je comprends bien, ça devrait être quelque chose comme ça;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        number++;
  printf("%d\n",number);
  }
}

et ceci arrondit également au multiple de 5 le plus proche au lieu de simplement arrondir;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        if (number%5 < 3)
            number--;
        else
        number++;
  printf("nearest multiple of 5 is: %d\n",number);
  }
}

1

Une autre façon de faire cela (sans multiplication explicite ou opérateurs de division):

def rnd(x, b=5):
    return round(x + min(-(x % b), b - (x % b), key=abs))

-3

Vous pouvez «tromper» int()pour arrondir au lieu d'arrondir vers le bas en ajoutant 0.5au nombre auquel vous passez int().


2
Cela ne répond pas réellement à la question
Uri Agassi
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.