C++: arrondir au multiple le plus proche d'un nombre
OK - je suis presque embarrassé de poster ceci ici (et je vais supprimer si quelqu'un vote pour fermer) car il semble comme une question de base.
est-ce la bonne façon de arrondir à un multiple D'un nombre en C++?
je sais qu'il y a d'autres questions liées à ceci mais je suis particulièrement intéressé de savoir quelle est la meilleure façon de faire ceci 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é mon intention. Ici en 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
EDIT: Merci pour toutes les réponses. Voici ce que j'ai cherché:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return numToRound;
}
int remainder = numToRound % multiple;
if (remainder == 0)
{
return numToRound;
}
return numToRound + multiple - remainder;
}
27 réponses
cela fonctionne pour les nombres positifs, pas sûr de négatif. Il utilise seulement math entier.
int roundUp(int numToRound, int multiple)
{
if (multiple == 0)
return numToRound;
int remainder = numToRound % multiple;
if (remainder == 0)
return numToRound;
return numToRound + multiple - remainder;
}
Edit: Voici une version qui fonctionne avec des nombres négatifs, si par "up" vous voulez dire un résultat qui est toujours >= l'entrée.
int roundUp(int numToRound, int multiple)
{
if (multiple == 0)
return numToRound;
int remainder = abs(numToRound) % multiple;
if (remainder == 0)
return numToRound;
if (numToRound < 0)
return -(abs(numToRound) - remainder);
else
return numToRound + multiple - remainder;
}
sans conditions:
int roundUp(int numToRound, int multiple)
{
assert(multiple);
return ((numToRound + multiple - 1) / multiple) * multiple;
}
cela fonctionne comme arrondissement à partir de zéro 1519100920 "pour les nombres négatifs
EDIT: Version qui fonctionne aussi pour les nombres négatifs
int roundUp(int numToRound, int multiple)
{
assert(multiple);
int isPositive = (int)(numToRound >= 0);
return ((numToRound + isPositive * (multiple - 1)) / multiple) * multiple;
}
si multiple
est une puissance de 2
int roundUp(int numToRound, int multiple)
{
assert(multiple && ((multiple & (multiple - 1)) == 0));
return (numToRound + multiple - 1) & -multiple;
}
Cela fonctionne quand le facteur sera toujours positif:
int round_up(int num, int factor)
{
return num + factor - 1 - (num - 1) % factor;
}
C'est une généralisation du problème de "comment puis-je savoir combien d'octets n bits? (A: (N bits + 7) / 8).
int RoundUp(int n, int roundTo)
{
// fails on negative? What does that mean?
if (roundTo == 0) return 0;
return ((n + roundTo - 1) / roundTo) * roundTo; // edit - fixed error
}
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
return ((numToRound - 1) / multiple + 1) * multiple;
}
Et pas besoin de se compliquer la vie avec des conditions
pour tous ceux qui cherchent une réponse courte et douce. C'est ce que j'ai utilisé. Pas de comptabilité pour les négatifs.
n - (n % r)
qui retournera le facteur précédent.
(n + r) - (n % r)
reviendra le prochain. Espérons que cela aide quelqu'un. :)
float roundUp(float number, float fixedBase) {
if (fixedBase != 0 && number != 0) {
float sign = number > 0 ? 1 : -1;
number *= sign;
number /= fixedBase;
int fixedPoint = (int) ceil(number);
number = fixedPoint * fixedBase;
number *= sign;
}
return number;
}
cela fonctionne pour n'importe quel nombre ou base de flotteur (par exemple, vous pouvez arrondir -4 à la plus proche 6,75). Il s'agit essentiellement de convertir en point fixe, d'y arrondir, puis de revenir en arrière. Il gère les négatifs en arrondissant à 0. Il gère également un round négatif à la valeur en transformant essentiellement la fonction en roundDown.
une version spécifique int ressemble à:
int roundUp(int number, int fixedBase) {
if (fixedBase != 0 && number != 0) {
int sign = number > 0 ? 1 : -1;
int baseSign = fixedBase > 0 ? 1 : 0;
number *= sign;
int fixedPoint = (number + baseSign * (fixedBase - 1)) / fixedBase;
number = fixedPoint * fixedBase;
number *= sign;
}
return number;
}
qui est plus ou moins la réponse de plinth, avec l'ajout d'entrée négative de soutien.
c'est l'approche c++ moderne 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).
#include <cmath>
#include <iostream>
template<typename T>
T roundMultiple( T value, T multiple )
{
if (multiple == 0) return value;
return static_cast<T>(std::round(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
int main()
{
std::cout << roundMultiple(39298.0, 100.0) << std::endl;
std::cout << roundMultiple(20930.0f, 1000.0f) << std::endl;
std::cout << roundMultiple(287399, 10) << std::endl;
}
mais vous pouvez facilement ajouter le support pour long long
et long double
avec la spécialisation de modèle comme montré ci-dessous:
template<>
long double roundMultiple<long double>( long double value, long double multiple)
{
if (multiple == 0.0l) return value;
return std::round(value/multiple)*multiple;
}
template<>
long long roundMultiple<long long>( long long value, long long multiple)
{
if (multiple == 0.0l) return value;
return static_cast<long long>(std::round(static_cast<long double>(value)/static_cast<long double>(multiple))*static_cast<long double>(multiple));
}
pour créer des fonctions pour arrondir, utilisez std::ceil
et pour arrondir toujours utiliser std::floor
. Mon exemple d'en haut est l'arrondissement en utilisant std::round
.
créer la fonction de modèle" arrondir "ou mieux connu sous le nom de" plafond rond "comme indiqué ci-dessous:
template<typename T>
T roundCeilMultiple( T value, T multiple )
{
if (multiple == 0) return value;
return static_cast<T>(std::ceil(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
créer la fonction de modèle" round down "ou mieux connue sous le nom de" round floor "comme suit:
template<typename T>
T roundFloorMultiple( T value, T multiple )
{
if (multiple == 0) return value;
return static_cast<T>(std::floor(static_cast<double>(value)/static_cast<double>(multiple))*static_cast<double>(multiple));
}
tout d'abord, votre condition d'erreur (multiple == 0) devrait probablement avoir une valeur de retour. Quoi? Je ne sais pas. Peut-être que tu veux faire une exception, ça dépend de toi. Mais, ne rien rendre est dangereux.
Deuxièmement, vous devriez vérifier que numToRound n'est pas déjà un multiple. Sinon, si vous ajoutez multiple
à roundDown
, vous obtiendrez la mauvaise réponse.
Troisièmement, vos moulages sont faux. Vous lancez numToRound
sur un entier, mais c'est déjà un entier. Vous devez lancer pour doubler avant la division, et de nouveau à int après la multiplication.
Enfin, que voulez-vous pour les nombres négatifs? Arrondissement " vers le haut "peut signifier arrondissement à zéro (arrondissement dans la même direction que les nombres positifs), ou à l'écart de zéro (un nombre négatif" plus grand"). Ou, peut-être que vous n'avez pas de soins.
Voici une version avec les trois premiers correctifs, mais je ne traite pas de la question négative:
int roundUp(int numToRound, int multiple)
{
if(multiple == 0)
{
return 0;
}
else if(numToRound % multiple == 0)
{
return numToRound
}
int roundDown = (int) (( (double) numToRound / multiple ) * multiple);
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
}
Rond de Puissance de Deux:
juste au cas où quelqu'un a besoin d'une solution pour les nombres positifs arrondis au plus proche multiple d'une puissance de deux (parce que c'est ainsi que j'ai fini ici):
// number: the number to be rounded (ex: 5, 123, 98345, etc.)
// pow2: the power to be rounded to (ex: to round to 16, use '4')
int roundPow2 (int number, int pow2) {
pow2--; // because (2 exp x) == (1 << (x -1))
pow2 = 0x01 << pow2;
pow2--; // because for any
//
// (x = 2 exp x)
//
// subtracting one will
// yield a field of ones
// which we can use in a
// bitwise OR
number--; // yield a similar field for
// bitwise OR
number = number | pow2;
number++; // restore value by adding one back
return number;
}
le numéro d'entrée restera le même s'il est déjà multiple.
Voici la sortie x86_64 que GCC donne avec -O2
ou -Os
(9Sep2013 Build-godbolt GCC online):
roundPow2(int, int):
lea ecx, [rsi-1]
mov eax, 1
sub edi, 1
sal eax, cl
sub eax, 1
or eax, edi
add eax, 1
ret
chaque ligne de code C correspond parfaitement à sa ligne dans l'Assemblée: http://goo.gl/DZigfX
chacune de ces instructions sont extrêmement rapide , de sorte que la fonction est extrêmement rapide aussi. Comme le code est si petit et rapide, il pourrait être utile de inline
la fonction lors de son utilisation.
crédit:
j'utilise:
template <class _Ty>
inline _Ty n_Align_Up(_Ty n_x, _Ty n_alignment)
{
assert(n_alignment > 0);
//n_x += (n_x >= 0)? n_alignment - 1 : 1 - n_alignment; // causes to round away from zero (greatest absolute value)
n_x += (n_x >= 0)? n_alignment - 1 : -1; // causes to round up (towards positive infinity)
//n_x += (_Ty(-(n_x >= 0)) & n_alignment) - 1; // the same as above, avoids branch and integer multiplication
//n_x += n_alignment - 1; // only works for positive numbers (fastest)
return n_x - n_x % n_alignment; // rounds negative towards zero
}
et pour les pouvoirs de deux:
template <class _Ty>
bool b_Is_POT(_Ty n_x)
{
return !(n_x & (n_x - 1));
}
template <class _Ty>
inline _Ty n_Align_Up_POT(_Ty n_x, _Ty n_pot_alignment)
{
assert(n_pot_alignment > 0);
assert(b_Is_POT(n_pot_alignment)); // alignment must be power of two
-- n_pot_alignment;
return (n_x + n_pot_alignment) & ~n_pot_alignment; // rounds towards positive infinity (i.e. negative towards zero)
}
notez que ces deux valeurs négatives rondes vers zéro (c'est-à-dire vers l'infini positif pour toutes les valeurs), ni l'une ni l'autre ne repose sur le débordement signé (qui n'est pas défini en C/C++).
Cela donne:
n_Align_Up(10, 100) = 100
n_Align_Up(110, 100) = 200
n_Align_Up(0, 100) = 0
n_Align_Up(-10, 100) = 0
n_Align_Up(-110, 100) = -100
n_Align_Up(-210, 100) = -200
n_Align_Up_POT(10, 128) = 128
n_Align_Up_POT(130, 128) = 256
n_Align_Up_POT(0, 128) = 0
n_Align_Up_POT(-10, 128) = 0
n_Align_Up_POT(-130, 128) = -128
n_Align_Up_POT(-260, 128) = -256
probablement plus sûr de lancer sur les flotteurs et d'utiliser ceil () - à moins que vous ne sachiez que la division int va produire le bon résultat.
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple
c++ arrondit chaque nombre vers le bas,donc si vous ajoutez 0.5 (si son 1.5 sera 2) mais 1.49 sera 1.99 donc 1.
EDIT - Désolé de ne pas vous voir voulait pour conclure, je dirais à l'aide d'un ceil() la méthode la place de l' +0.5
Eh bien pour une chose, puisque je ne comprends pas vraiment ce que vous voulez faire ,les lignes""
int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc);
pourrait certainement être raccourci en
int roundUp = roundDown + multiple;
return roundUp;
peut être cela peut aider:
int RoundUpToNearestMultOfNumber(int val, int num)
{
assert(0 != num);
return (floor((val + num) / num) * num);
}
pour toujours arrondir
int alwaysRoundUp(int n, int multiple)
{
if (n % multiple != 0) {
n = ((n + multiple) / multiple) * multiple;
// Another way
//n = n - n % multiple + multiple;
}
return n;
}
alwaysRoundUp(1, 10) -> 10
alwaysRoundUp(5, 10) -> 10
alwaysRoundUp(10, 10) -> 10
pour toujours arrondir
int alwaysRoundDown(int n, int multiple)
{
n = (n / multiple) * multiple;
return n;
}
alwaysRoundDown(1, 10) -> 0
alwaysRoundDown(5, 10) -> 0
always ROUNDDOWN(10, 10) -> 10
pour contourner la voie normale
int normalRound(int n, int multiple)
{
n = ((n + multiple/2)/multiple) * multiple;
return n;
}
normalRound(1, 10) -> 0
normalRound(5, 10) -> 10
normalRound(10, 10) -> 10
j'ai trouvé un algorithme quelque peu similaire à celui affiché ci-dessus:
int [(|x/+n-1)/n]*[(nx)|| x/], où x est une valeur d'entrée utilisateur et n le multiple utilisé.
il 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.
pour le nombre négatif:
il devrait être vraiment facile de faire cela, mais l'opérateur standard modulo % 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 les nombres négatifs. Alors roundUp est vraiment simple.
public static int mod(int x, int n)
{
return ((x % n) + n) % n;
}
public static int roundUp(int numToRound, int multiple)
{
return numRound + mod(-numToRound, multiple);
}
C'est ce que je ferais:
#include <cmath>
int roundUp(int numToRound, int multiple)
{
// if our number is zero, return immediately
if (numToRound == 0)
return multiple;
// if multiplier is zero, return immediately
if (multiple == 0)
return numToRound;
// how many times are number greater than multiple
float rounds = static_cast<float>(numToRound) / static_cast<float>(multiple);
// determine, whether if number is multiplier of multiple
int floorRounds = static_cast<int>(floor(rounds));
if (rounds - floorRounds > 0)
// multiple is not multiplier of number -> advance to the next multiplier
return (floorRounds+1) * multiple;
else
// multiple is multiplier of number -> return actual multiplier
return (floorRounds) * multiple;
}
le code pourrait ne pas être optimal, mais je préfère le code propre que la performance à sec.
int roundUp (int numToRound, int multiple)
{
return multiple * ((numToRound + multiple - 1) / multiple);
}
bien que:
- ne fonctionne pas pour les nombres négatifs
- ne fonctionne pas si numRound + de multiples débordements
suggérerait d'utiliser plutôt des entiers non signés, qui ont un comportement de débordement défini.
vous obtiendrez une exception est multiple == 0, mais ce n'est pas un problème bien défini dans ce cas de toute façon.
c:
int roundUp(int numToRound, int multiple)
{
return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}
et pour votre ~/.bashrc:
roundup()
{
echo $(( ? ((+-1)/)* : ))
}
j'utilise une combinaison de modules pour annuler l'addition du reste si x
est déjà un multiple:
int round_up(int x, int div)
{
return x + (div - x % div) % div;
}
nous trouvons l'inverse du reste puis module qu'avec le diviseur à nouveau de l'annuler si elle est le diviseur lui-même puis Ajouter x
.
round_up(19, 3) = 21
voici ma solution basée sur la suggestion de L'OP, et les exemples donnés par tout le monde. Puisque la plupart de tout le monde le cherchait pour manipuler des nombres négatifs, cette solution fait justement cela, sans l'utilisation de n'importe quelles fonctions spéciales, c.-à-d. abs, et autres.
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 au bas. Après la version arrondie vers le bas est calculé, puis il fait les mathématiques nécessaires pour arrondir, soit dans le sens négatif ou positif.
notez aussi qu'aucune fonction spéciale n'est utilisée pour calculer quoi que ce soit, il y a donc une petite augmentation de vitesse.
int RoundUp(int n, int multiple)
{
// prevent divide by 0 by returning n
if (multiple == 0) return n;
// calculate the rounded down version
int roundedDown = n / multiple * multiple;
// if the rounded version and original are the same, then return the original
if (roundedDown == n) return n;
// handle negative number and round up according to the sign
// NOTE: if n is < 0 then subtract the multiple, otherwise add it
return (n < 0) ? roundedDown - multiple : roundedDown + multiple;
}
/// Rounding up 'n' to the nearest multiple of number 'b'.
/// - Not tested for negative numbers.
/// \see http://stackoverflow.com/questions/3407012/
#define roundUp(n,b) ( (b)==0 ? (n) : ( ((n)+(b)-1) - (((n)-1)%(b)) ) )
/// \c test->roundUp().
void test_roundUp() {
// yes_roundUp(n,b) ( (b)==0 ? (n) : ( (n)%(b)==0 ? n : (n)+(b)-(n)%(b) ) )
// yes_roundUp(n,b) ( (b)==0 ? (n) : ( ((n + b - 1) / b) * b ) )
// no_roundUp(n,b) ( (n)%(b)==0 ? n : (b)*( (n)/(b) )+(b) )
// no_roundUp(n,b) ( (n)+(b) - (n)%(b) )
if (true) // couldn't make it work without (?:)
{{ // test::roundUp()
unsigned m;
{ m = roundUp(17,8); } ++m;
assertTrue( 24 == roundUp(17,8) );
{ m = roundUp(24,8); }
assertTrue( 24 == roundUp(24,8) );
assertTrue( 24 == roundUp(24,4) );
assertTrue( 24 == roundUp(23,4) );
{ m = roundUp(23,4); }
assertTrue( 24 == roundUp(21,4) );
assertTrue( 20 == roundUp(20,4) );
assertTrue( 20 == roundUp(19,4) );
assertTrue( 20 == roundUp(18,4) );
assertTrue( 20 == roundUp(17,4) );
assertTrue( 17 == roundUp(17,0) );
assertTrue( 20 == roundUp(20,0) );
}}
}
cela obtient les résultats que vous recherchez pour les entiers positifs:
#include <iostream>
using namespace std;
int roundUp(int numToRound, int multiple);
int main() {
cout << "answer is: " << roundUp(7, 100) << endl;
cout << "answer is: " << roundUp(117, 100) << endl;
cout << "answer is: " << roundUp(477, 100) << endl;
cout << "answer is: " << roundUp(1077, 100) << endl;
cout << "answer is: " << roundUp(52,20) << endl;
cout << "answer is: " << roundUp(74,30) << endl;
return 0;
}
int roundUp(int numToRound, int multiple) {
if (multiple == 0) {
return 0;
}
int result = (int) (numToRound / multiple) * multiple;
if (numToRound % multiple) {
result += multiple;
}
return result;
}
Et voici les sorties:
answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90
je pense que cela devrait vous aider. J'ai écrit le programme ci-dessous en C.
# include <stdio.h>
int main()
{
int i, j;
printf("\nEnter Two Integers i and j...");
scanf("%d %d", &i, &j);
int Round_Off=i+j-i%j;
printf("The Rounded Off Integer Is...%d\n", Round_Off);
return 0;
}
cela fonctionne pour moi mais n'a pas essayé de traiter les négatifs
public static int roundUp(int numToRound, int multiple) {
if (multiple == 0) {
return 0;
} else if (numToRound % multiple == 0) {
return numToRound;
}
int mod = numToRound % multiple;
int diff = multiple - mod;
return numToRound + diff;
}