385 votes

Comment arrondir le résultat d'une division entière ?

Je pense en particulier à la manière d'afficher les contrôles de pagination, lorsqu'on utilise un langage tel que C# ou Java.

Si j'ai x que je veux afficher dans des morceaux de y par page, combien de pages seront nécessaires ?

1 votes

J'ai raté quelque chose ? y/x + 1 fonctionne très bien (à condition que vous sachiez que l'opérateur / arrondit toujours vers le bas).

64 votes

@rikkit - si y et x sont égaux, y/x + 1 est un de trop.

1 votes

Pour ceux qui viennent de découvrir ça, cette réponse à une question de dupe évite la conversion inutile en double y évite les problèmes de débordement en plus de fournir une explication claire.

561voto

Ian Nelson Points 20020

J'ai trouvé une solution élégante :

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Fuente: Conversion des numéros, Roland Backhouse, 2001

15 votes

-1 à cause du bogue de débordement signalé par Brandon DuRette

36 votes

M. Evidence dit : N'oubliez pas de vous assurer que recordsPerPage n'est pas égal à zéro.

7 votes

Bon travail, je ne peux pas croire que le C# n'a pas de plafond d'entiers.

239voto

rjmunro Points 10522

Convertir en virgule flottante et inversement semble être une énorme perte de temps au niveau du CPU.

La solution de Ian Nelson :

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

On peut le simplifier :

int pageCount = (records - 1) / recordsPerPage + 1;

D'après les informations disponibles, cette méthode ne présente pas le bogue de dépassement de capacité signalé par Brandon DuRette et, comme elle ne l'utilise qu'une seule fois, il n'est pas nécessaire de stocker le paramètre recordsPerPage, surtout s'il provient d'une fonction coûteuse permettant de récupérer la valeur d'un fichier de configuration ou autre.

Cela pourrait être inefficace, si config.fetch_value utilisait une consultation de base de données ou autre :

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');

Cela crée une variable dont vous n'avez pas vraiment besoin, ce qui a probablement des implications (mineures) en termes de mémoire et représente tout simplement trop de travail de saisie :

int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Il s'agit d'une seule ligne, qui ne récupère les données qu'une seule fois :

int pageCount = (records - 1) / config.fetch_value('records per page') + 1;

6 votes

+1, le problème des enregistrements nuls qui renvoient toujours 1 pageCount est en fait pratique, puisque je voudrais toujours avoir 1 page, montrant le placeholder/fausse ligne de "aucun enregistrement ne correspond à vos critères", permet d'éviter tout problème de "0 page count" dans le contrôle de pagination que vous utilisez.

33 votes

Sachez que les deux solutions ne renvoient pas le même pageCount pour les enregistrements nuls. Cette version simplifiée renvoie 1 pageCount pour des enregistrements nuls, alors que la version de Roland Backhouse renvoie 0 pageCount. C'est bien si c'est ce que vous désirez, mais les deux équations ne sont pas équivalentes lorsqu'elles sont exécutées par la division d'entiers à la C#/Java.

13 votes

Petite modification pour la clarté pour les personnes qui le scannent et qui manquent les bodmas en passant de la solution Nelson à la simplification (comme je l'ai fait la première fois !), la simplification avec les parenthèses est... int pageCount = ((records - 1) / recordsPerPage) + 1 ;

100voto

Huppie Points 4805

En C#, la solution consiste à convertir les valeurs en un double (puisque Math.Ceiling prend un double) :

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);

En java, vous devriez faire la même chose avec Math.ceil().

4 votes

Pourquoi cette réponse est-elle si loin alors que l'op demande explicitement du C# !

2 votes

Vous devez également convertir la sortie en int parce que Math.Ceiling renvoie un double o decimal en fonction des types d'entrée.

24 votes

Parce qu'il est extrêmement inefficace

82voto

Nick Berardi Points 31361

Cela devrait vous donner ce que vous voulez. Le problème, c'est lorsque les nombres sont inégaux. Ainsi, s'il y a une page partielle, il faut aussi ajouter une page.

int x = number_of_items;
int y = items_per_page;

// with out library
int pages = x/y + (x % y > 0 ? 1 : 0)

// with library
int pages = (int)Math.Ceiling((double)x / (double)y);

8 votes

X/y + ! !(x % y) évite la branche pour les langages de type C. Il y a cependant de fortes chances que votre compilateur le fasse de toute façon.

2 votes

+1 pour ne pas déborder comme les réponses ci-dessus... bien que convertir des ints en doubles juste pour Math.ceiling et ensuite de nouveau est une mauvaise idée dans un code sensible aux performances.

4 votes

@RhysUlerich cela ne fonctionne pas en c# (on ne peut pas convertir directement un int en bool). La solution de rjmunro est la seule façon d'éviter le branchement je pense.

19voto

Brandon DuRette Points 3034

La solution de calcul des nombres entiers fournie par Ian est intéressante, mais elle souffre d'un bogue de dépassement des nombres entiers. En supposant que les variables sont toutes int la solution pourrait être réécrite pour utiliser long les mathématiques et éviter le bug :

int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;

Si records est un long mais le problème demeure. La solution du module ne présente pas le bogue.

6 votes

Je ne pense pas qu'il soit réaliste de penser que vous allez rencontrer ce bug dans le scénario présenté. 2^31 enregistrements, c'est beaucoup de choses à parcourir.

8 votes

1 votes

@finnw : AFAICS, il n'y a pas d'exemple réel sur cette page, juste un rapport de quelqu'un qui a trouvé le bug dans un scénario théorique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X