C ++: arrotondamento per eccesso al multiplo più vicino di un numero


168

OK - Sono quasi imbarazzato pubblicando questo qui (e cancellerò se qualcuno vota per chiudere) in quanto sembra una domanda di base.

È questo il modo corretto di arrotondare per eccesso a un multiplo di un numero in C ++?

So che ci sono altre domande relative a questo, ma sono particolarmente interessato a sapere qual è il modo migliore per farlo in 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);
}

Aggiornamento: mi dispiace, probabilmente non ho chiarito l'intenzione. Ecco alcuni esempi:

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

3
Hai un errore nella tua logica - diciamo che voglio arrotondare 4 al multiplo più vicino di 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; così roundCalc = 6. Sto assumendo che tu voglia restituire 4 in quel caso.
Niki Yoshiuchi,

questo non funziona per roundUp (30,30). Dà 60 come risposta, dovrebbe ancora dare 30 come risposta ..
bsobaid

@bsobaid: controlla la mia risposta in fondo. È leggermente più semplice rispetto ad altre soluzioni qui, anche se dovrebbero funzionare anche queste
Niklas B.

3
I casi di test mancano in modo evidente esempi che coinvolgono numeri negativi, casi in cui la divisione è esatta, casi in cui la divisione è quasi esatta e casi in cui i numeri sono molto vicini ai limiti dell'intervallo di int.

1
Robben_Ford_Fan_boy, La modifica con la risposta cercata dovrebbe essere rimossa. Se differisce dalle risposte fornite, puoi pubblicare la tua risposta. Allo stato attuale, quella risposta ha problemi che dovrebbero essere affrontati nella sezione risposta.
chux - Ripristina Monica il

Risposte:


161

Questo funziona per numeri positivi, non sono sicuro di negativo. Utilizza solo la matematica intera.

int roundUp(int numToRound, int multiple)
{
    if (multiple == 0)
        return numToRound;

    int remainder = numToRound % multiple;
    if (remainder == 0)
        return numToRound;

    return numToRound + multiple - remainder;
}

Modifica: ecco una versione che funziona con numeri negativi, se per "su" intendi un risultato che è sempre> = l'input.

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

+1 Secondo me, sicuramente la soluzione più bella e più leggibile.
Robben_Ford_Fan_boy il

1
Aggiungi if(number<0){ multiple = multiple*(-1); }all'inizio per arrotondare i numeri negativi nella giusta direzione
Josh

4
@Josh: Perché usare la moltiplicazione? if(number<0) multiple = -multipleè più facile.
md5,

questo non funziona per roundUp (30,30). Dà 60 come risposta, dovrebbe comunque dare 30 come risposta.
Bsobaid,

@bsobaid impossibile. Il if (remainder == 0)test dovrebbe occuparsi di quel caso. Funziona per me: ideone.com/Waol7B
Mark Ransom

114

Senza condizioni:

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

Funziona come arrotondare per difetto a zero per i numeri negativi

EDIT: versione che funziona anche per numeri negativi

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

test


If multipleè una potenza di 2 (più veloce in ~ 3.7 volte http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

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

test


24
+1 per la potenza della versione 2. Molto utile in quanto evita totalmente il costo di moltiplicazioni, divisioni o modulo.
Nikos C.,

Sei sicuro che questi algoritmi non abbiano precondizioni? E i numeri negativi? Il comportamento sembra non definito in pre-C ++ 11 .
cubuspl42,

> Che dire dei numeri negativi? Come descritto, questo funziona per numeri negativi come arrotondamento da zero.
KindDragon,

Ho letto "arrotondamento per eccesso" come significato per arrotondamento verso l'infinito positivo, non per arrotondamento da zero.

8
Si noti che & ~(x - 1)è lo stesso & -xdell'aritmetica del complemento a due.
Todd Lehman,

39

Questo funziona quando il fattore sarà sempre positivo:

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

Modifica: questo ritorna round_up(0,100)=100. Si prega di vedere il commento di Paul di seguito per una soluzione che ritorna round_up(0,100)=0.


1
Sembra essere il caso più breve che gestisce il caso "già multiplo".
Harningt,

1
La migliore soluzione in termini di numero di operazioni costose. Utilizza solo un singolo divison e nessuna moltiplicazione
Niklas B.

3
round_up (0, 100) == 100 invece di 0 come nella risposta accettata
Gregory

7
Non dovrebbe essere num + factor - 1 - (num + factor - 1) % factor?
Paul

6
num - 1 - (num - 1) % factor + factoresegue lo stesso calcolo senza il rischio di overflow di numeri interi.

24

Questa è una generalizzazione del problema di "come faccio a sapere quanti byte n bit prenderà? (A: (n bit + 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
}

1
Questo non arrotonda al multiplo successivo di un numero.
aaaa bbbb,

7
Mi piace questa soluzione perché se roundTo sarà una potenza di 2, puoi eliminare il / e * e finire con nient'altro che operazioni economiche (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz

@Trejkaz no. Dovrebbe essere (x = roundTo - 1; return (n+x)&~roundTo;)come nella mia risposta
KindDragon,

@KindDragon che produce il risultato sbagliato per me, ma se lo correggo per dire ~ x invece di ~ roundTo, ottengo il risultato atteso. Su Java 8 comunque.
Trejkaz,

@KindDragon: la maschera AND deve essere 0xFFF...000, non 0xFFF7FFFo qualcosa del genere, quindi vuoi la negazione del complemento di 2 ( -: meno) su una potenza di 2, o capovolgi bit su una meno di una potenza di 2 (inverso del complemento,: ~tilde non meno). Così (n+x) & ~xo (n-roundTo+1) & -roundTo.
Peter Cordes,

14
int roundUp(int numToRound, int multiple)
{
 if(multiple == 0)
 {
  return 0;
 }
 return ((numToRound - 1) / multiple + 1) * multiple;  
}

E non c'è bisogno di scherzare con le condizioni


11

Per chiunque cerchi una risposta breve e dolce. Questo è quello che ho usato. Nessuna contabilità per negativi.

n - (n % r)

Ciò restituirà il fattore precedente.

(n + r) - (n % r)

Restituirà il prossimo. Spero che questo aiuti qualcuno. :)


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

Funziona con qualsiasi numero float o base (ad es. Puoi arrotondare -4 al più vicino 6.75). In sostanza si sta convertendo in punto fisso, arrotondando lì, quindi riconvertendo. Gestisce i negativi arrotondando LONTANO da 0. Gestisce anche un round negativo al valore trasformando essenzialmente la funzione in roundDown.

Una versione specifica int è simile a:

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

Qual è la risposta più o meno dello zoccolo, con il supporto di input negativo aggiunto.


Ho testato il codice float roundUp con doppio, funziona per me. Risolve davvero il mio problema.
Ashif,

1
Che dire di 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); }O scambiare ceil per round per ottenere arrotondamenti.
Troyseph,

8

Questo è il moderno approccio c ++ che utilizza una funzione template che funziona con float, double, long, int e short (ma non per long long e long double a causa dei doppi valori usati).

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

Ma puoi facilmente aggiungere supporto per long longe long doublecon la specializzazione dei modelli come mostrato di seguito:

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

Per creare funzioni da arrotondare, usare std::ceile per arrotondare sempre std::floor. Il mio esempio dall'alto è arrotondare usando std::round.

Creare la funzione modello "arrotondamento per eccesso" o meglio conosciuta come "soffitto tondo" come mostrato di seguito:

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

Creare la funzione modello "arrotondamento per difetto" o meglio nota come "piano arrotondato" come mostrato di seguito:

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

1
più 1, anche se alcune persone potrebbero trovare più ragionevole restituire 0 quando mulitple == 0
stijn

3
Attenzione, perché la conversione di int64_t in double può essere con perdita di dati, quindi non è abbastanza generico come potrebbe apparire.
Adrian McCarthy,

@AdrianMcCarthy Sì, devi creare le specializzazioni dei template corrette, come mostrato sopra. Come puoi vedere, implemento due funzioni aggiuntive per long longe long double. Lo stesso deve essere fatto ovviamente per le altre due funzioni.
Flovdis,

Penso che questo sia di gran lunga il più lento di tutti, ma non dovrebbe esserlo. Tutto quello che devi fare è std :: enable_if_t e fare due rami per numeri interi e float. Puoi anche fare un uso migliore di numeric_limits e vedere se la mantissa è abbastanza grande da adattarsi effettivamente al valore. Ciò aggiungerebbe alla sicurezza.
il suino

5

Prima di tutto, la tua condizione di errore (più == 0) dovrebbe probabilmente avere un valore di ritorno. Che cosa? Non lo so. Forse vuoi fare un'eccezione, dipende da te. Ma restituire nulla è pericoloso.

Secondo, dovresti verificare che numToRound non sia già un multiplo. Altrimenti, quando si aggiunge multiplearoundDown , otterrai la risposta sbagliata.

In terzo luogo, i tuoi cast sono sbagliati. Tu lancinumToRound a un numero intero, ma è già un numero intero. È necessario eseguire il cast per raddoppiare prima della divisione e tornare a int dopo la moltiplicazione.

Infine, cosa vuoi per i numeri negativi? Arrotondare "su" può significare arrotondare a zero (arrotondando nella stessa direzione dei numeri positivi) o allontanarsi da zero (un numero negativo "più grande"). O forse non ti interessa.

Ecco una versione con le prime tre correzioni, ma non mi occupo del problema negativo:

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

@Peter È? Ho pensato che int / intavrebbe restituito un int, che non è quello che volevamo.
Mike Caron,

int / int restituisce effettivamente un int, ma è esattamente quello che vuoi. Ad esempio, numToRound = 7, multiple = 3. 7/3 = 2.
Peter Ruderman

4

Round to Power of Two:

Nel caso in cui qualcuno abbia bisogno di una soluzione per numeri positivi arrotondati al multiplo più vicino di una potenza di due (perché è così che sono finito qui):

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

Il numero di input rimarrà lo stesso se è già un multiplo.

Ecco l'output x86_64 fornito da GCC con -O2o -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

Ogni riga di codice C corrisponde perfettamente alla sua riga nell'assieme: http://goo.gl/DZigfX

Ognuna di queste istruzioni è estremamente veloce , quindi anche la funzione è estremamente veloce. Poiché il codice è così piccolo e veloce, potrebbe essere utileinline funzione quando lo si utilizza.


Credito:


1
Esattamente quello che stavo cercando. Grazie!
kiyo,

1
int roundUpPow2 (int num, int pow2) {return num + (pow2 - 1) & ~ (pow2 - 1); } è circa il 30% più veloce e più facile da usare (passi 16 non 4 per arrotondare al multiplo successivo di 16.
Axel Rietschin,

3

Sto usando:

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
}

e per poteri di due:

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

Si noti che entrambi questi valori arrotondati negativi verso zero (che significa arrotondamento all'infinito positivo per tutti i valori), nessuno dei due si basa su un overflow con segno (che non è definito in C / C ++).

Questo da:

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

Uso il tuo n_Align_Up_POTda quando l'ho visto nella classe TList di Delphi. Ha le sue restrizioni, come l'allineamento (multiplo) essendo una potenza di 2, ma raramente è un problema perché lo uso principalmente per ottenere / verificare l'allineamento corretto per SMID. È fantastico e sembra che non molte persone lo sappiano.
user1593842

2

Probabilmente è più sicuro lanciare float e usare ceil () - a meno che tu non sappia che la divisione int produrrà il risultato corretto.


1
Si noti che solo il doppio può contenere 54 bit di significato su macchine basate su x86. Se hai 64 bit, alla fine fallirà.
il maiale il

Il doppio standard IEEE754 non può ma x64 cpus ha un virgola mobile interna a 80 bit, quindi le operazioni su un singolo numero sono affidabili
Martin Beckett

1
Sebbene ciò sia vero, hai pochissimo controllo su tale arrotondamento da C / C ++. Dipende dalle impostazioni della parola di controllo e può effettivamente arrotondare a meno di 80 bit. Inoltre hai SSE e altri set di istruzioni SIMD che non hanno tale intermedio esteso (il compilatore vettorializzante potrebbe usarli facilmente).
il maiale il

2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

C ++ arrotonda ogni numero verso il basso, quindi se aggiungi 0,5 (se il suo 1,5 sarà 2) ma 1,49 sarà 1,99 quindi 1.

EDIT - Mi dispiace non aver visto che volevi arrotondare, suggerirei di utilizzare un metodo ceil () invece di +0.5


2

bene per una cosa, dal momento che non capisco davvero cosa vuoi fare, le linee

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

potrebbe sicuramente essere abbreviato in

int roundUp = roundDown + multiple;
return roundUp;

2

può essere questo può aiutare:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}

Perché usare la divisione floor e integer? Non c'è nulla da pavimentare. Se fosse doppio, potresti almeno ereditare la gestione di valori negativi.
il suino

2

Per arrotondare sempre

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


Per arrotondare sempre

int alwaysRoundDown(int n, int multiple)
{
    n = (n / multiple) * multiple;

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Per arrotondare nel modo 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

Arrotonda al multiplo più vicino che risulta essere una potenza di 2

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

Questo può essere utile per l'allocazione lungo le cache, dove l'incremento di arrotondamento desiderato è una potenza di due, ma il valore risultante deve essere solo un multiplo di esso. Sul gcccorpo di questa funzione genera 8 istruzioni di assemblaggio senza divisione o rami.

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

1

Ho trovato un algoritmo che è in qualche modo simile a quello pubblicato sopra:

int [(| x | + n-1) / n] * [(nx) / | x |], dove x è un valore di input dell'utente e n è il multiplo in uso.

Funziona con tutti i valori x, dove x è un numero intero (positivo o negativo, incluso zero). L'ho scritto appositamente per un programma C ++, ma questo può essere praticamente implementato in qualsiasi lingua.


1

Per numToRound negativo:

Dovrebbe essere davvero facile farlo, ma l'operatore modulo% standard non gestisce i numeri negativi come ci si potrebbe aspettare. Ad esempio -14% 12 = -2 e non 10. La prima cosa da fare è ottenere un operatore modulo che non restituisce mai numeri negativi. Quindi roundUp è davvero semplice.

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

Questo è quello che vorrei fare:

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

Il codice potrebbe non essere ottimale, ma preferisco il codice pulito rispetto alle prestazioni a secco.


Lanciare intper floatperdere prontamente precisione e dare risposte errate.
chux - Ripristina Monica il

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

sebbene:

  • non funzionerà con numeri negativi
  • non funzionerà se numRound + overflow multipli

suggerirei invece di utilizzare numeri interi senza segno, che ha definito il comportamento di overflow.

Otterrai un'eccezione è multiple == 0, ma in ogni caso non è un problema ben definito.


1

c:

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

e per il tuo ~ / .bashrc:

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

1

Uso una combinazione di moduli per annullare l'aggiunta del resto se xè già un multiplo:

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

Troviamo l'inverso del resto quindi modulo che con il divisore di nuovo per annullarlo se è il divisore stesso quindi aggiungere x.

round_up(19, 3) = 21

1

Ecco la mia soluzione basata sul suggerimento del PO e sugli esempi forniti da tutti gli altri. Poiché quasi tutti lo cercavano per gestire i numeri negativi, questa soluzione fa proprio questo, senza l'uso di alcuna funzione speciale, ad esempio addominali e simili.

Evitando il modulo e usando invece la divisione, il numero negativo è un risultato naturale, sebbene sia arrotondato per difetto. Dopo aver calcolato la versione arrotondata per difetto, esegue la matematica necessaria per arrotondare, in direzione negativa o positiva.

Si noti inoltre che non vengono utilizzate funzioni speciali per calcolare nulla, quindi c'è un piccolo aumento di velocità lì.

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

Errore con RoundUp(INT_MIN, -1)as n / multipleè intoverflow.
chux - Ripristina Monica il

1

Penso che questo dovrebbe aiutarti. Ho scritto il seguente programma in 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
/// 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

Questo sta ottenendo i risultati che stai cercando per numeri interi positivi:

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

Ed ecco gli output:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90

0

Penso che funzioni:

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

-1

Questo funziona per me ma non ha provato a gestire i negativi

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

-3

Ecco una soluzione super semplice per mostrare il concetto di eleganza. Fondamentalmente è per gli snap alla griglia.

(pseudo codice)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;

hai verificato la tua idea prima di inviarla? esso fornisce una risposta
yaodav,

Questo non è nemmeno un codice valido.
user13783520
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.