Étant donné les valeurs entières x
et y
, C et C ++ renvoient tous les deux comme quotient q = x/y
le plancher de l'équivalent en virgule flottante. Je suis intéressé par une méthode de retour du plafond à la place. Par exemple, ceil(10/5)=2
et ceil(11/5)=3
.
L'approche évidente implique quelque chose comme:
q = x / y;
if (q * y < x) ++q;
Cela nécessite une comparaison et une multiplication supplémentaires; et d'autres méthodes que j'ai vues (utilisées en fait) impliquent le casting en tant que float
ou double
. Existe-t-il une méthode plus directe qui évite la multiplication supplémentaire (ou une deuxième division) et la branche, et qui évite également la conversion en nombre à virgule flottante?
q = x/y + (x % y != 0);
assezRéponses:
Pour les nombres positifs
Pour arrondir ...
ou (en évitant le débordement en x + y)
la source
x/y
comme le plafond de la division. C90 n'a pas précisé comment arrondir, et je ne pense pas que la norme C ++ actuelle le fasse non plus.q = x / y;
Pour les nombres positifs:
la source
La réponse de Sparky est un moyen standard de résoudre ce problème, mais comme je l'ai également écrit dans mon commentaire, vous courez le risque de débordements. Cela peut être résolu en utilisant un type plus large, mais que se passe-t-il si vous souhaitez diviser
long long
s?La réponse de Nathan Ernst fournit une solution, mais elle implique un appel de fonction, une déclaration de variable et un conditionnel, ce qui le rend pas plus court que le code OP et probablement encore plus lent, car il est plus difficile à optimiser.
Ma solution est la suivante:
Il sera légèrement plus rapide que le code OP, car le modulo et la division sont effectués en utilisant la même instruction sur le processeur, car le compilateur peut voir qu'ils sont équivalents. Au moins gcc 4.4.1 effectue cette optimisation avec l'indicateur -O2 sur x86.
En théorie, le compilateur pourrait incorporer l'appel de fonction dans le code de Nathan Ernst et émettre la même chose, mais gcc ne l'a pas fait quand je l'ai testé. Cela peut être dû au fait qu'il lierait le code compilé à une seule version de la bibliothèque standard.
En conclusion, rien de tout cela n'a d'importance sur une machine moderne, sauf si vous êtes dans une boucle extrêmement serrée et que toutes vos données sont dans des registres ou dans le cache L1. Sinon, toutes ces solutions seront également rapides, à l'exception peut-être de Nathan Ernst, qui pourrait être considérablement plus lent si la fonction doit être récupérée de la mémoire principale.
la source
q = (x > 0)? 1 + (x - 1)/y: (x / y);
q = x / y + (x % y > 0);
c'est plus facile que l'? :
expression?Vous pouvez utiliser la
div
fonction dans cstdlib pour obtenir le quotient et le reste en un seul appel, puis gérer le plafond séparément, comme ci-dessousla source
return res.quot + !!res.rem;
:)Que dis-tu de ça? (nécessite y non négatif, ne l'utilisez donc pas dans les rares cas où y est une variable sans garantie de non-négativité)
J'ai réduit
y/y
à un, éliminant le termex + y - 1
et avec lui toute possibilité de débordement.J'évite de
x - 1
m'enrouler quandx
est un type non signé et contient zéro.Pour signé
x
, négatif et zéro se combinent toujours en un seul cas.Probablement pas un énorme avantage sur un CPU polyvalent moderne, mais ce serait beaucoup plus rapide dans un système embarqué que n'importe quelle autre bonne réponse.
la source
Il existe une solution à la fois positive et négative,
x
mais uniquement pour le positify
avec une seule division et sans branches:Notez que si
x
est positif, la division est vers zéro et nous devons ajouter 1 si le rappel n'est pas nul.Si
x
est négatif alors la division est vers zéro, c'est ce dont nous avons besoin, et nous n'ajouterons rien parce que cex % y
n'est pas positifla source
Cela fonctionne pour les nombres positifs ou négatifs:
S'il y a un reste, vérifie si
x
ety
sont du même signe et ajoute en1
conséquence.la source
J'aurais plutôt commenté mais je n'ai pas de représentant suffisamment élevé.
Pour autant que je sache, pour les arguments positifs et un diviseur qui est une puissance de 2, c'est le moyen le plus rapide (testé dans CUDA):
Pour les arguments positifs génériques uniquement, j'ai tendance à le faire comme suit:
la source
q = x/y + !!(x % y);
comparentq = x/y + (x % y == 0);
et lesq = (x + y - 1) / y;
solutions en termes de performances dans le CUDA contemporain.forme générique simplifiée,
Pour une réponse plus générique, les fonctions C ++ pour la division entière avec une stratégie d'arrondi bien définie
la source
Compiler avec O3, le compilateur effectue bien l'optimisation.
la source