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; 
}  
135
demandé sur Robben_Ford_Fan_boy 2010-08-04 19:19:23

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;
}
136
répondu Mark Ransom 2015-10-29 15:17:37

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

Essais


si multiple est une puissance de 2

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

Essais

88
répondu KindDragon 2017-08-03 10:06:32

Cela fonctionne quand le facteur sera toujours positif:

int round_up(int num, int factor)
{
    return num + factor - 1 - (num - 1) % factor;
}
32
répondu xlq 2014-06-14 21:16:17

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
}
22
répondu plinth 2010-08-04 16:24:50
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

14
répondu doron 2010-08-04 15:58:13

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

10
répondu Askanison4 2013-07-17 11:14:47
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.

8
répondu Dolphin 2015-02-19 23:06:16

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));
}
7
répondu Flovdis 2014-03-13 22:04:31

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);
}
5
répondu Mike Caron 2010-08-04 15:24:22

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:

3
répondu haneefmubarak 2017-04-13 12:19:15

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
3
répondu the swine 2017-04-03 14:33:37

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.

2
répondu Martin Beckett 2010-08-04 15:23:23
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

2
répondu Michal Ciechan 2010-08-04 15:23:46

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;
2
répondu Jesse Naugher 2010-08-04 15:26:18

peut être cela peut aider:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
2
répondu Arsen 2013-09-20 14:25:35

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

2
répondu onmyway133 2014-01-20 15:03:27

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.

1
répondu Joshua Wade 2011-01-26 01:17:42

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);
}
1
répondu user990343 2013-02-15 12:14:00

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.

1
répondu Gotcha 2014-03-07 22:09:30
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.

1
répondu user3392484 2014-03-12 19:52:25

c:

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

et pour votre ~/.bashrc:

roundup()
{
  echo $((  ? ((+-1)/)* :  ))
}
1
répondu nhed 2014-03-14 02:24:36

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
1
répondu Nick Bedford 2017-01-21 22:27:03

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;
}
1
répondu weatx 2018-07-29 14:20:35
/// 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) );
}}
}
0
répondu Adolfo 2014-02-14 13:30:38

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
0
répondu Dave 2014-03-08 00:31:00

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;
}
0
répondu Neel 2018-09-30 06:21:08

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;
}
-1
répondu user1100538 2012-05-31 20:22:08