C ++: arredondando para o múltiplo mais próximo de um número

168

OK - Estou quase envergonhado postando isso aqui (e vou excluir se alguém votar para fechar), pois parece uma pergunta básica.

É a maneira correta de arredondar para um múltiplo de um número em C ++?

Sei que existem outras perguntas relacionadas a isso, mas estou especificamente interessado em saber qual é a melhor maneira de fazer isso em 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);
}

Atualização: Desculpe, provavelmente não deixei clara a intenção. aqui estão alguns exemplos:

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
fonte
3
Você tem um erro na sua lógica - digamos que eu queira arredondar 4 até o múltiplo mais próximo de 2. roundDown = (4/2) * 2 = 4; roundUp = 4 + 2; então roundCalc = 6. Estou assumindo que você desejaria retornar 4 nesse caso.
Niki Yoshiuchi
isso não funciona para roundUp (30,30). Ele dá 60 como resposta, ele ainda deve dar 30 como resposta ..
bsobaid
@bsobaid: Confira minha resposta na parte inferior. É um pouco mais simples do que outras soluções aqui, embora aqueles deve funcionar também
Niklas B.
3
Seus casos de teste são exemplos ausentes em termos visuais que envolvem números negativos, casos em que a divisão é exata, casos em que a divisão é quase exata e casos em que os números estão muito próximos dos limites do intervalo de int.
1
Robben_Ford_Fan_boy, A edição com a resposta que você procurou deve ser removida. Se for diferente das respostas fornecidas, você poderá postar sua própria resposta. Tal como está, essa resposta tem problemas que devem ser abordados na seção de respostas.
chux - Restabelece Monica

Respostas:

161

Isso funciona para números positivos, não tenho certeza sobre negativos. Ele usa apenas matemática inteira.

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: Aqui está uma versão que funciona com números negativos, se por "up" você quer dizer um resultado que é sempre> = a entrada.

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
fonte
+1 Na minha opinião, definitivamente a solução mais agradável e legível.
Robben_Ford_Fan_boy
1
Adicione if(number<0){ multiple = multiple*(-1); }no início o arredondamento dos números negativos na direção certa
Josh
4
@ Jos: Por que usar multiplicação? if(number<0) multiple = -multipleé mais fácil.
Md5
isso não funciona para roundUp (30,30). Dá 60 como resposta, ainda deve dar 30 como resposta.
precisa saber é o seguinte
@bsobaid impossível. O if (remainder == 0)teste deve cuidar desse caso. Funciona para mim: ideone.com/Waol7B
Mark Ransom
114

Sem condições:

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

Isso funciona como arredondar para zero para números negativos

EDIT: Versão que também funciona para números negativos

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

Testes


Se multiplefor uma potência de 2 (mais rápido em ~ 3,7 vezes http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )

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

Testes

KindDragon
fonte
24
+1 para o poder da versão 2. Muito útil, pois evita totalmente o custo de multiplicações, divisões ou módulos.
Nikos C.
Você tem certeza de que esses algoritmos não têm pré-condições? E os números negativos? O comportamento parece estar indefinido no pré-C ++ 11 .
cubuspl42
> E os números negativos? Conforme descrito, isso funciona para números negativos, como arredondar para longe de zero.
KindDragon 3/15
Eu li "arredondando para cima" como significando arredondamento para o infinito positivo, não arredondando para longe do zero.
8
Observe que & ~(x - 1)é o mesmo & -xda aritmética do complemento de dois.
Todd Lehman
39

Isso funciona quando o fator sempre será positivo:

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

Edit: Isso retorna round_up(0,100)=100. Por favor, veja o comentário de Paulo abaixo para obter uma solução que retorne round_up(0,100)=0.

xlq
fonte
1
Parece ser o caso mais curto que lida com o caso 'já é múltiplo'.
harningt
1
Melhor solução em termos de número de operações caras. Ele utiliza apenas um único Divison e nenhuma multiplicação
Niklas B.
3
round_up (0, 100) == 100 em vez de 0, como na resposta aceita
Gregory
7
Não deveria ser num + factor - 1 - (num + factor - 1) % factor?
Paul
6
num - 1 - (num - 1) % factor + factorfaz o mesmo cálculo sem o risco de excesso de número inteiro.
24

Esta é uma generalização do problema de "como descubro quantos bytes n bits serão necessários?" (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
}
plinto
fonte
1
Isso não arredonda para o próximo múltiplo de um número.
Aaaa bbbb
7
Eu gosto dessa solução porque se roundTo será uma potência de 2, você poderá eliminar o / e * e acabar com nada além de operações baratas (x = roundTo - 1; return (n + x) & ~ x;)
Trejkaz
@Trejkaz nope. Deve ser (x = roundTo - 1; return (n+x)&~roundTo;)como na minha resposta
KindDragon
@KindDragon que produz o resultado errado para mim, mas se eu o corrigir para dizer ~ x em vez de ~ roundTo, obtenho o resultado esperado. No Java 8 de qualquer maneira.
Trejkaz
@KindDragon: A máscara AND precisa ser 0xFFF...000, não 0xFFF7FFFou algo assim, então você quer a negação do complemento de 2 (( -menos)) com uma potência de 2 ou girar bit em uma menos que uma potência de 2 (complemento de uma inversa ~: til não menos). Então (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;  
}

E não há necessidade de mexer com as condições

Doron
fonte
11

Para quem procura uma resposta curta e agradável. Isto é o que eu usei. Não há contabilização de negativos.

n - (n % r)

Isso retornará o fator anterior.

(n + r) - (n % r)

Voltará o próximo. Espero que isso ajude alguém. :)

ligação aaron
fonte
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;
}

Isso funciona para qualquer número flutuante ou base (por exemplo, você pode arredondar -4 para o valor mais próximo a 6,75). Em essência, está convertendo em ponto fixo, arredondando para lá e depois convertendo de volta. Ele lida com negativos arredondando AWAY de 0. Ele também lida com um valor negativo ao transformar essencialmente a função em roundDown.

Uma versão específica do int é semelhante 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 é a resposta mais ou menos do plinto, com o suporte adicional de entrada negativa.

Golfinho
fonte
Eu testei o código float roundUp com double, funciona para mim. Realmente resolve meu problema.
Ashif
1
E quanto a 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); }trocar de teto por rodada para obter arredondamentos?
Troyseph 13/02/19
8

Essa é a abordagem moderna do c ++ usando uma função de modelo que está trabalhando para float, double, long, int e short (mas não por long long e long double por causa dos valores duplos usados).

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

Mas você pode adicionar facilmente suporte para long longe long doublecom especialização de modelos, como mostrado abaixo:

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

Para criar funções para arredondar, use std::ceile para arredondar sempre o uso std::floor. Meu exemplo acima é de arredondamento usando std::round.

Crie a função de modelo "arredondar para cima" ou mais conhecida como "teto redondo", como mostrado abaixo:

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

Crie a função de modelo "arredondar para baixo" ou mais conhecida como "andar arredondado", como mostrado abaixo:

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
fonte
1
mais 1, embora algumas pessoas possam encontrá-lo mais razoável para retornar 0 quando mulitple == 0
stijn
3
Cuidado, pois a conversão de int64_t para o dobro pode ser prejudicial, portanto, não é tão genérico quanto pode parecer.
Adrian McCarthy
@AdrianMcCarthy Sim, você precisa criar as especializações de modelo corretas, como mostrado acima. Como você pode ver, eu implemento duas funções adicionais para long longe long double. O mesmo deve ser feito para as outras duas funções, obviamente.
Flovdis
Eu acho que isso é de longe o mais lento de todos, mas não teria que ser. Tudo o que você precisa fazer é std :: enable_if_t e executar duas ramificações para números inteiros e flutuantes. Você também pode usar melhor os limites numéricos e ver se a mantissa é grande o suficiente para realmente ajustar o valor. Isso aumentaria a segurança.
the swine
5

Primeiro, sua condição de erro (múltiplo == 0) provavelmente deve ter um valor de retorno. O que? Eu não sei. Talvez você queira lançar uma exceção, isso é com você. Mas retornar nada é perigoso.

Segundo, você deve verificar se numToRound ainda não é múltiplo. Caso contrário, quando você adiciona multiplea roundDown, você vai ter a resposta errada.

Em terceiro lugar, seus elencos estão errados. Você transmite numToRoundpara um número inteiro, mas já é um número inteiro. Você precisa converter para dobrar antes da divisão e voltar para int após a multiplicação.

Por fim, o que você deseja para números negativos? Arredondar "para cima" pode significar arredondar para zero (arredondar na mesma direção que números positivos) ou afastar-se de zero (um número negativo "maior"). Ou talvez você não se importe.

Aqui está uma versão com as três primeiras correções, mas não trato do 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);
}
Mike Caron
fonte
@ Peter É? Presumi que int / intretornaria um int, que não é o que queríamos.
Mike Caron
int / int realmente retorna um int, mas é exatamente isso que você deseja. Por exemplo, numToRound = 7, múltiplo = 3. 7/3 = 2. #
314 Peter Ruderman
4

Volta ao poder de dois:

Caso alguém precise de uma solução para números positivos arredondados para o múltiplo mais próximo de uma potência de dois (porque foi assim que acabei aqui):

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

O número de entrada permanecerá o mesmo se já for múltiplo.

Aqui está a saída x86_64 fornecida pelo GCC -O2ou -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

Cada linha de código C corresponde perfeitamente à sua linha na montagem: http://goo.gl/DZigfX

Cada uma dessas instruções é extremamente rápida , portanto, a função também é extremamente rápida. Como o código é tão pequeno e rápido, pode ser útilinline a função ao usá-lo.


Crédito:

haneefmubarak
fonte
1
Exatamente o que eu estava procurando. Obrigado!
kiyo
1
int roundUpPow2 (int num, int pow2) {retorna num + (pow2 - 1) & ~ (pow2 - 1); } é cerca de 30% mais rápido e mais fácil de usar (você passa 16, não 4, para arredondar para o próximo múltiplo de 16.
Axel Rietschin 03/09/16
3

Estou a usar:

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 por potências de dois:

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

Observe que esses dois valores negativos arredondados em direção a zero (que significa arredondar para o infinito positivo para todos os valores), nenhum deles depende do estouro assinado (que não é definido em C / C ++).

Isto dá:

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
os porcos
fonte
Eu uso o seu n_Align_Up_POTdesde que o vi na classe TList do Delphi. Ele tem restrições, como o alinhamento (múltiplo) sendo uma potência de 2, mas isso raramente é um problema, porque eu o uso principalmente para obter / verificar o alinhamento correto do SMID. É incrível e parece que muitas pessoas não sabem disso.
user1593842
2

Provavelmente é mais seguro converter em flutuadores e usar ceil () - a menos que você saiba que a divisão int produzirá o resultado correto.

Martin Beckett
fonte
1
Observe que o double apenas pode armazenar 54 bits de significando em máquinas baseadas em x86. Se você tem ints de 64 bits, isso acabará por falhar.
the swine
IEEE754 duplo padrão não pode deixar de x64 CPUs tem um 80bit ponto flutuante interna para operações em um único número são confiáveis
Martin Beckett
1
Embora isso seja verdade, você tem muito pouco controle sobre esse arredondamento do C / C ++. Depende das configurações da palavra de controle e, na verdade, pode arredondar para menos de 80 bits. Além disso, você tem SSE e outros conjuntos de instruções SIMD que não possuem esse intermediário estendido (o compilador de vetorização poderia usá-los facilmente).
the
2
int noOfMultiples = int((numToRound / multiple)+0.5);
return noOfMultiples*multiple

C ++ arredonda cada número para baixo, portanto, se você adicionar 0,5 (se 1,5 for 2), mas 1,49 será 1,99, portanto 1.

EDIT - Desculpe, não vi que você queria arredondar, eu sugeriria o uso de um método ceil () em vez de +0,5

Michal Ciechan
fonte
2

bem, por um lado, já que eu realmente não entendo o que você quer fazer, as linhas

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

definitivamente poderia ser reduzido para

int roundUp = roundDown + multiple;
return roundUp;
Jesse Naugher
fonte
2

pode ser que isso possa ajudar:

int RoundUpToNearestMultOfNumber(int val, int num)
{
  assert(0 != num);
  return (floor((val + num) / num) * num);
}
Arsen
fonte
Por que usar divisão de piso e número inteiro? Não há nada para andar. Se fosse o dobro, você poderia pelo menos herdar a manipulação de valores negativos.
the swine
2

Para arredondar 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


Para arredondar sempre para baixo

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

    return n;
}

alwaysRoundDown (1, 10) -> 0

alwaysRoundDown (5, 10) -> 0

alwaysRoundDown (10, 10) -> 10


Para arredondar o caminho normal

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
fonte
2

Arredonde para o múltiplo mais próximo que seja uma potência de 2

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

Isso pode ser útil para alocar ao longo de universitários, onde o incremento de arredondamento desejado é um poder de dois, mas o valor resultante precisa apenas ser um múltiplo dele. No gcccorpo desta função gera 8 instruções de montagem sem divisão ou ramificações.

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

Eu encontrei um algoritmo que é um pouco semelhante ao postado acima:

int [(| x | + n-1) / n] * [(nx) / | x |], em que x é um valor de entrada do usuário en é o múltiplo em uso.

Ele funciona para todos os valores x, onde x é um número inteiro (positivo ou negativo, incluindo zero). Eu o escrevi especificamente para um programa C ++, mas isso pode ser implementado basicamente em qualquer idioma.

Joshua Wade
fonte
1

Para numToRound negativo:

Deve ser muito fácil fazer isso, mas o operador padrão do módulo% não lida com números negativos, como seria de esperar. Por exemplo, -14% 12 = -2 e não 10. A primeira coisa a fazer é obter um operador de módulo que nunca retorna números negativos. Então roundUp é realmente simples.

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
fonte
1

Isto é o que eu faria:

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

O código pode não ser o ideal, mas prefiro o código limpo do que o desempenho seco.

Peguei vocês
fonte
A transmissão intpara o floatprontamente perde a precisão e gera respostas incorretas.
chux - Reinstala Monica
1
int roundUp (int numToRound, int multiple)
{
  return multiple * ((numToRound + multiple - 1) / multiple);
}

Apesar:

  • não funcionará para números negativos
  • não funcionará se numRound + vários estouros

sugeriria usar números inteiros não assinados, que definiu o comportamento de estouro.

Você receberá uma exceção múltipla == 0, mas, nesse caso, não é um problema bem definido.

user3392484
fonte
1

c:

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

e para o seu ~ / .bashrc:

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

Eu uso uma combinação de módulo para anular a adição do restante, se xjá é um múltiplo:

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

Encontramos o inverso do restante e, em seguida, o módulo com o divisor novamente para anulá-lo, se for o próprio divisor, e então adicionar x.

round_up(19, 3) = 21
Nick Bedford
fonte
1

Aqui está minha solução com base na sugestão do OP e nos exemplos dados por todos os outros. Como quase todo mundo estava procurando por ele para lidar com números negativos, esta solução faz exatamente isso, sem o uso de funções especiais, como abdominais, etc.

Ao evitar o módulo e usar a divisão, o número negativo é um resultado natural, embora seja arredondado para baixo. Depois que a versão arredondada é calculada, ele faz a matemática necessária para arredondar, na direção negativa ou positiva.

Observe também que nenhuma função especial é usada para calcular nada; portanto, há um pequeno aumento de velocidade 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;
}
weatx
fonte
Falha com RoundUp(INT_MIN, -1)como n / multipleé intestouro.
chux - Restabelece Monica
1

Eu acho que isso deve ajudá-lo. Eu escrevi o programa abaixo em 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
fonte
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
fonte
0

Isso está obtendo os resultados que você procura para números inteiros positivos:

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

E aqui estão as saídas:

answer is: 100
answer is: 200
answer is: 500
answer is: 1100
answer is: 60
answer is: 90
Dave
fonte
0

Eu acho que isso funciona:

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

Isso funciona para mim, mas não tentou lidar com negativos

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
fonte
-2

Aqui está uma solução super simples para mostrar o conceito de elegância. É basicamente para snaps à grade.

(pseudo-código)

nearestPos = Math.Ceil( numberToRound / multiple ) * multiple;
Indivelope
fonte
Você checou sua ideia antes de enviar? dosent dar resposta
atual
Esse nem é um código válido.
user13783520