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
int
.Respostas:
Isso funciona para números positivos, não tenho certeza sobre negativos. Ele usa apenas matemática inteira.
Edit: Aqui está uma versão que funciona com números negativos, se por "up" você quer dizer um resultado que é sempre> = a entrada.
fonte
if(number<0){ multiple = multiple*(-1); }
no início o arredondamento dos números negativos na direção certaif(number<0) multiple = -multiple
é mais fácil.if (remainder == 0)
teste deve cuidar desse caso. Funciona para mim: ideone.com/Waol7BSem condições:
Isso funciona como arredondar para zero para números negativos
EDIT: Versão que também funciona para números negativos
Testes
Se
multiple
for uma potência de 2 (mais rápido em ~ 3,7 vezes http://quick-bench.com/sgPEZV9AUDqtx2uujRSa3-eTE80 )Testes
fonte
& ~(x - 1)
é o mesmo& -x
da aritmética do complemento de dois.Isso funciona quando o fator sempre será positivo:
Edit: Isso retorna
round_up(0,100)=100
. Por favor, veja o comentário de Paulo abaixo para obter uma solução que retorneround_up(0,100)=0
.fonte
num + factor - 1 - (num + factor - 1) % factor
?num - 1 - (num - 1) % factor + factor
faz o mesmo cálculo sem o risco de excesso de número inteiro.Esta é uma generalização do problema de "como descubro quantos bytes n bits serão necessários?" (A: (n bits + 7) / 8).
fonte
(x = roundTo - 1; return (n+x)&~roundTo;)
como na minha resposta0xFFF...000
, não0xFFF7FFF
ou 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) & ~x
ou(n-roundTo+1) & -roundTo
.E não há necessidade de mexer com as condições
fonte
Para quem procura uma resposta curta e agradável. Isto é o que eu usei. Não há contabilização de negativos.
Isso retornará o fator anterior.
Voltará o próximo. Espero que isso ajude alguém. :)
fonte
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:
Qual é a resposta mais ou menos do plinto, com o suporte adicional de entrada negativa.
fonte
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?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).
Mas você pode adicionar facilmente suporte para
long long
elong double
com especialização de modelos, como mostrado abaixo:Para criar funções para arredondar, use
std::ceil
e para arredondar sempre o usostd::floor
. Meu exemplo acima é de arredondamento usandostd::round
.Crie a função de modelo "arredondar para cima" ou mais conhecida como "teto redondo", como mostrado abaixo:
Crie a função de modelo "arredondar para baixo" ou mais conhecida como "andar arredondado", como mostrado abaixo:
fonte
long long
elong double
. O mesmo deve ser feito para as outras duas funções, obviamente.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
multiple
aroundDown
, você vai ter a resposta errada.Em terceiro lugar, seus elencos estão errados. Você transmite
numToRound
para 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:
fonte
int / int
retornaria um int, que não é o que queríamos.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):
O número de entrada permanecerá o mesmo se já for múltiplo.
Aqui está a saída x86_64 fornecida pelo GCC
-O2
ou-Os
(9Sep2013 Build - godbolt GCC online):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 útil
inline
a função ao usá-lo.Crédito:
fonte
Estou a usar:
e por potências de dois:
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á:
fonte
n_Align_Up_POT
desde 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.Provavelmente é mais seguro converter em flutuadores e usar ceil () - a menos que você saiba que a divisão int produzirá o resultado correto.
fonte
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
fonte
bem, por um lado, já que eu realmente não entendo o que você quer fazer, as linhas
definitivamente poderia ser reduzido para
fonte
pode ser que isso possa ajudar:
fonte
Para arredondar sempre
alwaysRoundUp (1, 10) -> 10
alwaysRoundUp (5, 10) -> 10
alwaysRoundUp (10, 10) -> 10
Para arredondar sempre para baixo
alwaysRoundDown (1, 10) -> 0
alwaysRoundDown (5, 10) -> 0
alwaysRoundDown (10, 10) -> 10
Para arredondar o caminho normal
normalRound (1, 10) -> 0
normalRound (5, 10) -> 10
normalRound (10, 10) -> 10
fonte
Arredonde para o múltiplo mais próximo que seja uma potência de 2
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
gcc
corpo desta função gera 8 instruções de montagem sem divisão ou ramificações.fonte
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.
fonte
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.
fonte
Isto é o que eu faria:
O código pode não ser o ideal, mas prefiro o código limpo do que o desempenho seco.
fonte
int
para ofloat
prontamente perde a precisão e gera respostas incorretas.Apesar:
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.
fonte
c:
e para o seu ~ / .bashrc:
fonte
Eu uso uma combinação de módulo para anular a adição do restante, se
x
já é um múltiplo: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
.fonte
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á.
fonte
RoundUp(INT_MIN, -1)
comon / multiple
éint
estouro.Eu acho que isso deve ajudá-lo. Eu escrevi o programa abaixo em C.
fonte
fonte
Isso está obtendo os resultados que você procura para números inteiros positivos:
E aqui estão as saídas:
fonte
Eu acho que isso funciona:
fonte
Isso funciona para mim, mas não tentou lidar com negativos
fonte
Aqui está uma solução super simples para mostrar o conceito de elegância. É basicamente para snaps à grade.
(pseudo-código)
fonte