C ++: arrondi au multiple le plus proche d'un nombre

168

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
Robben_Ford_Fan_boy
la source
3
Vous avez une erreur dans votre logique - disons que je veux arrondir 4 au multiple le plus proche de 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; donc roundCalc = 6. Je suppose que vous voudriez retourner 4 dans ce cas.
Niki Yoshiuchi
cela ne fonctionne pas pour roundUp (30,30). Il donne 60 comme réponse, il devrait quand même donner 30 comme réponse ..
bsobaid
@bsobaid: Découvrez ma réponse en bas. C'est un peu plus simple que d'autres solutions ici, bien que celles-ci devraient également fonctionner
Niklas B.
3
Vos scénarios de test manquent manifestement d'exemples impliquant des nombres négatifs, des cas où la division est exacte, des cas où la division est presque exacte et des cas où les nombres sont très proches des limites de la plage de int.
1
Robben_Ford_Fan_boy, La modification avec la réponse que vous avez recherchée devrait être supprimée. Si elle diffère des réponses données, vous pouvez publier votre propre réponse. En l'état, cette réponse présente des problèmes qui devraient être abordés dans la section des réponses.
chux

Réponses:

161

Cela fonctionne pour les nombres positifs, pas sûr de négatifs. Il n'utilise que des nombres entiers.

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 entendez 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;
}
Mark Ransom
la source
+1 À mon avis, certainement la solution la plus agréable et la plus lisible.
Robben_Ford_Fan_boy
1
Ajouter if(number<0){ multiple = multiple*(-1); }au début pour arrondir les nombres négatifs dans la bonne direction
Josh
4
@Josh: Pourquoi utiliser la multiplication? if(number<0) multiple = -multipleest plus facile.
md5 le
cela ne fonctionne pas pour roundUp (30,30). Il donne 60 comme réponse, il devrait encore donner 30 comme réponse.
bsobaid
@bsobaid impossible. Le if (remainder == 0)test devrait prendre en charge ce cas. Cela fonctionne pour moi: ideone.com/Waol7B
Mark Ransom
115

Sans conditions:

int roundUp(int numToRound, int multiple) 
{
    assert(multiple);
    return ((numToRound + multiple - 1) / multiple) * multiple;
}

Cela fonctionne comme un arrondi à zéro pour les nombres négatifs

EDIT: Version qui fonctionne également 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;
}

Des tests


Si multipleest une puissance de 2 (plus rapide en ~ 3,7 fois http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

int roundUp(int numToRound, int multiple) 
{
    assert(multiple && ((multiple & (multiple - 1)) == 0));
    return (numToRound + multiple - 1) & -multiple;
}

Des tests

KindDragon
la source
24
+1 pour la puissance de la version 2. Très utile car il évite totalement le coût des multiplications, divisions ou modulo.
Nikos C.
Êtes-vous sûr que ces algorithmes n'ont pas de conditions préalables? Et les nombres négatifs? Le comportement semble indéfini dans la version pré-C ++ 11 .
cubuspl42
> Et les nombres négatifs? Comme décrit, cela fonctionne pour les nombres négatifs comme l'arrondi à partir de zéro.
KindDragon
J'ai lu «arrondi» comme signifiant arrondi vers l'infini positif, pas arrondi à partir de zéro.
8
Notez que & ~(x - 1)c'est la même chose que & -xpour l'arithmétique du complément à deux.
Todd Lehman
39

Cela fonctionne lorsque le facteur sera toujours positif:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}

Edit: Cela revient round_up(0,100)=100. Veuillez consulter le commentaire de Paul ci-dessous pour une solution qui revient round_up(0,100)=0.

xlq
la source
1
Cela semble être le cas le plus court qui gère le cas «déjà un multiple».
harningt
1
Meilleure solution en termes de nombre d'opérations coûteuses. Il n'utilise qu'une seule division et aucune multiplication
Niklas B.
3
round_up (0, 100) == 100 au lieu de 0 comme dans la réponse acceptée
Gregory
7
Cela ne devrait-il pas être le cas num + factor - 1 - (num + factor - 1) % factor?
Paul
6
num - 1 - (num - 1) % factor + factorfait le même calcul sans risque de débordement d'entier.
24

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).

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
}
socle
la source
1
Cela ne arrondit pas au prochain multiple d'un nombre.
aaaa bbbb
7
J'aime cette solution car si roundTo sera une puissance de 2, vous pourrez éliminer le / et * et vous retrouver avec rien d'autre que des opérations bon marché (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz
@Trejkaz non. Cela devrait être (x = roundTo - 1; return (n+x)&~roundTo;)comme dans ma réponse
KindDragon
@KindDragon qui produit le mauvais résultat pour moi, mais si je le corrige pour dire ~ x au lieu de ~ roundTo, j'obtiens le résultat attendu. Sur Java 8 en tout cas.
Trejkaz
@KindDragon: Le masque AND doit être 0xFFF...000, non 0xFFF7FFFou 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) & ~xou (n-roundTo+1) & -roundTo.
Peter Cordes
14
int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}

Et pas besoin de jouer avec les conditions

Doron
la source
11

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.

n - (n % r)

Cela renverra le facteur précédent.

(n + r) - (n % r)

Je reviendrai le prochain. J'espère que cela aide quelqu'un. :)

aaron-bond
la source
9
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 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 à:

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;
}

Ce qui est plus ou moins la réponse du socle, avec le support d'entrée négatif ajouté.

Dauphin
la source
J'ai testé le code float roundUp avec double, cela fonctionne pour moi. Résout vraiment mon problème.
Ashif
1
Qu'en est-il 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.
Troyseph
8

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).

#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 un support pour long longet long doubleavec la spécialisation de modèle comme indiqué 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, utiliser std::ceilet toujours arrondir l'utilisation std::floor. Mon exemple ci-dessus est l'arrondi en utilisant std::round.

Créez la fonction de modèle «arrondi» ou mieux connue 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éez la fonction de modèle «arrondi vers le bas» ou mieux connue sous le nom de «plancher rond», comme indiqué ci-dessous:

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));
}
Flovdis
la source
1
plus 1, bien que certaines personnes puissent trouver plus raisonnable de renvoyer 0 quand mulitple == 0
stijn
3
Attention, car la conversion de int64_t en double peut être avec perte, donc ce n'est pas aussi générique que cela puisse paraître.
Adrian McCarthy
@AdrianMcCarthy Oui, vous devez créer des spécialisations de modèle correctes comme indiqué ci-dessus. Comme vous pouvez le voir, j'implémente deux fonctions supplémentaires pour long longet long double. Il faut évidemment faire la même chose pour les deux autres fonctions.
Flovdis
Je pense que c'est de loin le plus lent de tous, mais ce ne devrait pas être le cas. Tout ce que vous avez à faire est de std :: enable_if_t et de faire deux branches pour les entiers et les flottants. Vous pouvez également faire un meilleur usage des numeric_limits et voir si la mantisse est suffisamment grande pour correspondre réellement à la valeur. Cela ajouterait à la sécurité.
le porc le
5

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 numToRounden 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:

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);
}
Mike Caron
la source
@Peter Vraiment? J'ai supposé que int / intcela renverrait un int, ce qui n'est pas ce que nous voulions.
Mike Caron
int / int renvoie effectivement un int, mais c'est précisément ce que vous voulez. Par exemple, numToRound = 7, multiple = 3. 7/3 = 2.
Peter Ruderman
4

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):

// 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 s'agit déjà d'un multiple.

Voici la sortie x86_64 que GCC donne avec -O2ou -Os(9Sep2013 Build - godbolt GCC en ligne):

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'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 à inlinela fonction lors de son utilisation.


Crédit:

haneefmubarak
la source
1
Exactement ce que je cherchais. Merci!
kiyo le
1
int roundUpPow2 (int num, int pow2) {return num + (pow2 - 1) & ~ (pow2 - 1); } est environ 30% plus rapide et plus facile à utiliser (vous passez 16 et non 4 pour arrondir au multiple
supérieur
3

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 puissances 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 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:

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
le porc
la source
J'utilise votre n_Align_Up_POTdepuis 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.
user1593842
2

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.

Martin Beckett
la source
1
Notez que le double ne peut contenir que 54 bits de significande sur les machines x86. Si vous avez des entiers 64 bits, cela échouera finalement.
le porc le
Le double standard IEEE754 ne peut pas mais les processeurs x64 ont une virgule flottante interne de 80 bits, de sorte que les opérations sur un seul nombre sont fiables
Martin Beckett
1
Bien que cela soit vrai, vous avez très peu de contrôle sur cet arrondi à partir de C / C ++. Cela dépend des paramètres du mot de contrôle et peut être arrondi à moins de 80 bits. Vous avez également SSE et d'autres jeux d'instructions SIMD qui n'ont pas d'intermédiaire étendu (le compilateur de vectorisation pourrait facilement les utiliser).
le porc
2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

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

Michal Ciechan
la source
2

eh bien pour une chose, puisque je ne comprends pas vraiment ce que tu veux faire, les lignes

int roundUp = roundDown + multiple;
int roundCalc = roundUp;
return (roundCalc); 

pourrait certainement être raccourci à

int roundUp = roundDown + multiple;
return roundUp;
Jesse Naugher
la source
2

peut-être que cela peut aider:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
Arsen
la source
Pourquoi utiliser la division par étage et par nombre entier? Il n'y a rien sur le sol. S'il était double, vous pourriez au moins hériter de la gestion des valeurs négatives.
le porc le
2

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

alwaysRoundDown (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

onmyway133
la source
2

Arrondir au multiple le plus proche qui se trouve être une puissance de 2

unsigned int round(unsigned int value, unsigned int multiple){
    return ((value-1u) & ~(multiple-1u)) + multiple;
}

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 gccle corps de cette fonction génère 8 instructions de montage sans division ni branches.

round(  0,  16) ->   0
round(  1,  16) ->  16
round( 16,  16) ->  16
round(257, 128) -> 384 (128 * 3)
round(333,   2) -> 334
Anne Quinn
la source
1

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.

Joshua Wade
la source
1

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.

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);
}
user990343
la source
1

Voici 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 n'est peut-être pas optimal, mais je préfère un code propre aux performances sèches.

Je t'ai eu
la source
La coulée intà floatperd facilement la précision et fait des réponses incorrectes.
chux
1
int roundUp (int numToRound, int multiple)
{
  return multiple * ((numToRound + multiple - 1) / multiple);
}

bien que:

  • ne fonctionnera pas pour les nombres négatifs
  • ne fonctionnera pas si numRound + plusieurs débordements

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.

user3392484
la source
1

c:

int roundUp(int numToRound, int multiple)
{
  return (multiple ? (((numToRound+multiple-1) / multiple) * multiple) : numToRound);
}

et pour votre ~ / .bashrc:

roundup()
{
  echo $(( ${2} ? ((${1}+${2}-1)/${2})*${2} : ${1} ))
}
nhed
la source
1

J'utilise une combinaison de module pour annuler l'ajout du reste si xc'est déjà un multiple:

int round_up(int x, int div)
{
    return x + (div - x % div) % div;
}

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.

round_up(19, 3) = 21
Nick Bedford
la source
1

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.

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;
}
weatx
la source
Échoue avec RoundUp(INT_MIN, -1)comme n / multipleest inttrop plein.
chux
1

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;
}
Neel
la source
0
/// 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) );
}}
}
Adolfo
la source
0

Ceci obtient les résultats que vous recherchez pour des 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
Dave
la source
0

Je pense que cela fonctionne:

int roundUp(int numToRound, int multiple) {
    return multiple? !(numToRound%multiple)? numToRound : ((numToRound/multiple)+1)*multiple: numToRound;
}
utilisateur13783520
la source
-1

Cela fonctionne pour moi mais je n'ai pas essayé de gérer 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;
}
user1100538
la source
-3

Voici une solution super simple pour montrer le concept d'élégance. C'est essentiellement pour les snaps de grille.

(pseudo code)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;
Indivelope
la source
avez-vous vérifié votre idée avant de la soumettre? il peut donner une réponse
précise
Ce n'est même pas un code valide.
user13783520