OK - Je suis presque gêné de poster ceci ici (et je supprimerai si quelqu'un vote pour fermer) car cela semble être une question basique.
Est-ce la bonne façon d'arrondir à un multiple d'un nombre en C ++?
Je sais qu'il y a d'autres questions liées à cela, mais je suis particulièrement intéressé de savoir quelle est la meilleure façon de le faire en C ++:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return numToRound;
}
int roundDown = ( (int) (numToRound) / multiple) * multiple;
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
}
Mise à jour: Désolé, je n'ai probablement pas précisé l'intention. Voici quelques exemples:
roundUp(7, 100)
//return 100
roundUp(117, 100)
//return 200
roundUp(477, 100)
//return 500
roundUp(1077, 100)
//return 1100
roundUp(52, 20)
//return 60
roundUp(74, 30)
//return 90
int
.Réponses:
Cela fonctionne pour les nombres positifs, pas sûr de négatifs. Il n'utilise que des nombres entiers.
Edit: Voici une version qui fonctionne avec des nombres négatifs, si par "up" vous entendez un résultat qui est toujours> = l'entrée.
la source
if(number<0){ multiple = multiple*(-1); }
au début pour arrondir les nombres négatifs dans la bonne directionif(number<0) multiple = -multiple
est plus facile.if (remainder == 0)
test devrait prendre en charge ce cas. Cela fonctionne pour moi: ideone.com/Waol7BSans conditions:
Cela fonctionne comme un arrondi à zéro pour les nombres négatifs
EDIT: Version qui fonctionne également pour les nombres négatifs
Des tests
Si
multiple
est une puissance de 2 (plus rapide en ~ 3,7 fois http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )Des tests
la source
& ~(x - 1)
c'est la même chose que& -x
pour l'arithmétique du complément à deux.Cela fonctionne lorsque le facteur sera toujours positif:
Edit: Cela revient
round_up(0,100)=100
. Veuillez consulter le commentaire de Paul ci-dessous pour une solution qui revientround_up(0,100)=0
.la source
num + factor - 1 - (num + factor - 1) % factor
?num - 1 - (num - 1) % factor + factor
fait le même calcul sans risque de débordement d'entier.C'est une généralisation du problème de "comment puis-je savoir combien d'octets n bits prendront? (A: (n bits + 7) / 8).
la source
(x = roundTo - 1; return (n+x)&~roundTo;)
comme dans ma réponse0xFFF...000
, non0xFFF7FFF
ou quelque chose, donc vous voulez soit la négation du complément de 2 (-
: moins) sur une puissance de 2, soit un bit-flip sur un moins d'une puissance de 2 (son complément inverse~
,: tilde pas moins). Alors(n+x) & ~x
ou(n-roundTo+1) & -roundTo
.Et pas besoin de jouer avec les conditions
la source
Pour tous ceux qui recherchent une réponse courte et douce. C'est ce que j'ai utilisé. Pas de prise en compte des négatifs.
Cela renverra le facteur précédent.
Je reviendrai le prochain. J'espère que cela aide quelqu'un. :)
la source
Cela fonctionne pour n'importe quel nombre flottant ou base (par exemple, vous pouvez arrondir -4 aux 6,75 près). Essentiellement, il s'agit d'une conversion en virgule fixe, d'un arrondi, puis d'une reconversion. Il gère les négatifs en arrondissant AWAY à partir de 0. Il gère également un arrondi négatif à la valeur en transformant essentiellement la fonction en roundDown.
Une version spécifique à int ressemble à:
Ce qui est plus ou moins la réponse du socle, avec le support d'entrée négatif ajouté.
la source
double round(double value, double multiple) { double sign = value; multiple = std::copysign(multiple, 1.0); value = std::copysign(value, 1.0); return std::copysign(multiple * std::ceil(value / multiple), sign); }
ou permutez ceil pour un tour pour arrondir.Il s'agit de l'approche moderne C ++ utilisant une fonction de modèle qui fonctionne pour float, double, long, int et short (mais pas pour long long et long double en raison des valeurs doubles utilisées).
Mais vous pouvez facilement ajouter un support pour
long long
etlong double
avec la spécialisation de modèle comme indiqué ci-dessous:Pour créer des fonctions pour arrondir, utiliser
std::ceil
et toujours arrondir l'utilisationstd::floor
. Mon exemple ci-dessus est l'arrondi en utilisantstd::round
.Créez la fonction de modèle «arrondi» ou mieux connue sous le nom de «plafond rond», comme indiqué ci-dessous:
Créez la fonction de modèle «arrondi vers le bas» ou mieux connue sous le nom de «plancher rond», comme indiqué ci-dessous:
la source
long long
etlong double
. Il faut évidemment faire la même chose pour les deux autres fonctions.Tout d'abord, votre condition d'erreur (multiple == 0) devrait probablement avoir une valeur de retour. Quoi? Je ne sais pas. Peut-être voulez-vous lever une exception, c'est à vous de décider. Mais ne rien renvoyer est dangereux.
Deuxièmement, vous devez vérifier que numToRound n'est pas déjà un multiple. Sinon, lorsque vous ajoutez
multiple
àroundDown
, vous obtiendrez la mauvaise réponse.Troisièmement, vos lancers sont faux. Vous convertissez
numToRound
en un entier, mais c'est déjà un entier. Vous devez lancer pour doubler avant la division et revenir à int après la multiplication.Enfin, que voulez-vous pour les nombres négatifs? Arrondir «vers le haut» peut signifier arrondir à zéro (arrondi dans le même sens que les nombres positifs), ou s'éloigner de zéro (un nombre négatif «plus grand»). Ou peut-être que vous ne vous en souciez pas.
Voici une version avec les trois premiers correctifs, mais je ne traite pas le problème négatif:
la source
int / int
cela renverrait un int, ce qui n'est pas ce que nous voulions.Arrondir à la puissance de deux:
Juste au cas où quelqu'un aurait besoin d'une solution pour les nombres positifs arrondis au multiple le plus proche d'une puissance de deux (car c'est comme ça que je me suis retrouvé ici):
Le numéro d'entrée restera le même s'il s'agit déjà d'un multiple.
Voici la sortie x86_64 que GCC donne avec
-O2
ou-Os
(9Sep2013 Build - godbolt GCC en ligne):Chaque ligne de code C correspond parfaitement à sa ligne dans l'assemblage: http://goo.gl/DZigfX
Chacune de ces instructions est extrêmement rapide , donc la fonction est également extrêmement rapide. Étant donné que le code est si petit et rapide, il peut être utile à
inline
la fonction lors de son utilisation.Crédit:
la source
J'utilise:
et pour les puissances de deux:
Notez que ces deux valeurs négatives arrondies vers zéro (ce qui signifie arrondir à l'infini positif pour toutes les valeurs), ni l'une ni l'autre ne repose sur un débordement signé (qui n'est pas défini en C / C ++).
Cela donne:
la source
n_Align_Up_POT
depuis que je l'ai vu dans la classe TList de Delphi. Il a ses restrictions, comme l'alignement (multiple) étant une puissance de 2, mais c'est rarement un problème car je l'utilise principalement pour obtenir / vérifier l'alignement correct pour SMID. C'est génial et il semble que peu de gens le sachent.Probablement plus sûr de lancer des flotteurs et d'utiliser ceil () - à moins que vous ne sachiez que la division int va produire le résultat correct.
la source
C ++ arrondit chaque nombre à la baisse, donc si vous ajoutez 0,5 (si c'est 1,5, ce sera 2) mais 1,49 sera 1,99 donc 1.
EDIT - Désolé, je n'ai pas vu que vous vouliez arrondir, je suggérerais d'utiliser une méthode ceil () au lieu de +0,5
la source
eh bien pour une chose, puisque je ne comprends pas vraiment ce que tu veux faire, les lignes
pourrait certainement être raccourci à
la source
peut-être que cela peut aider:
la source
Pour toujours arrondir
alwaysRoundUp (1, 10) -> 10
alwaysRoundUp (5, 10) -> 10
alwaysRoundUp (10, 10) -> 10
Pour toujours arrondir
alwaysRoundDown (1, 10) -> 0
alwaysRoundDown (5, 10) -> 0
alwaysRoundDown (10, 10) -> 10
Pour contourner la voie normale
normalRound (1, 10) -> 0
normalRound (5, 10) -> 10
normalRound (10, 10) -> 10
la source
Arrondir au multiple le plus proche qui se trouve être une puissance de 2
Cela peut être utile lors de l'allocation le long des lignes de cache, où l'incrément d'arrondi souhaité est une puissance de deux, mais la valeur résultante ne doit être qu'un multiple de celle-ci. Sur
gcc
le corps de cette fonction génère 8 instructions de montage sans division ni branches.la source
J'ai trouvé un algorithme qui est un peu similaire à celui publié ci-dessus:
int [(| x | + n-1) / n] * [(nx) / | x |], où x est une valeur d'entrée utilisateur et n est le multiple utilisé.
Cela fonctionne pour toutes les valeurs x, où x est un entier (positif ou négatif, y compris zéro). Je l'ai écrit spécifiquement pour un programme C ++, mais cela peut être implémenté dans n'importe quel langage.
la source
Pour numToRound négatif:
Cela devrait être très facile à faire, mais l'opérateur modulo% standard ne gère pas les nombres négatifs comme on pourrait s'y attendre. Par exemple -14% 12 = -2 et non 10. La première chose à faire est d'obtenir l'opérateur modulo qui ne renvoie jamais de nombres négatifs. Ensuite, roundUp est vraiment simple.
la source
Voici ce que je ferais:
Le code n'est peut-être pas optimal, mais je préfère un code propre aux performances sèches.
la source
int
àfloat
perd facilement la précision et fait des réponses incorrectes.bien que:
suggérerait d'utiliser à la place des entiers non signés, ce qui a défini un comportement de débordement.
Vous obtiendrez une exception multiple == 0, mais ce n'est pas un problème bien défini dans ce cas de toute façon.
la source
c:
et pour votre ~ / .bashrc:
la source
J'utilise une combinaison de module pour annuler l'ajout du reste si
x
c'est déjà un multiple:On trouve l'inverse du reste puis module qu'avec le diviseur à nouveau pour l'annuler si c'est le diviseur lui-même puis additionner
x
.la source
Voici ma solution basée sur la suggestion du PO et les exemples donnés par tout le monde. Comme presque tout le monde le recherchait pour gérer les nombres négatifs, cette solution fait exactement cela, sans utiliser de fonctions spéciales, c'est-à-dire abs, etc.
En évitant le module et en utilisant la division à la place, le nombre négatif est un résultat naturel, bien qu'il soit arrondi vers le bas. Une fois la version arrondie inférieure calculée, elle effectue les calculs nécessaires pour arrondir vers le haut, dans le sens négatif ou positif.
Notez également qu'aucune fonction spéciale n'est utilisée pour calculer quoi que ce soit, il y a donc une petite augmentation de vitesse.
la source
RoundUp(INT_MIN, -1)
commen / multiple
estint
trop plein.Je pense que cela devrait vous aider. J'ai écrit le programme ci-dessous en C.
la source
la source
Ceci obtient les résultats que vous recherchez pour des entiers positifs:
Et voici les sorties:
la source
Je pense que cela fonctionne:
la source
Cela fonctionne pour moi mais je n'ai pas essayé de gérer les négatifs
la source
Voici une solution super simple pour montrer le concept d'élégance. C'est essentiellement pour les snaps de grille.
(pseudo code)
la source