Estou esquecendo de algo? y / x + 1 funciona muito bem (desde que você saiba que o operador / sempre arredonda para baixo).
Rikkit 7/08
51
@rikkit - se y e x são iguais, y / x + 1 é muito alto.
196 Ian Ian
11
Para quem acabou de encontrar isso, esta resposta a uma pergunta idiota evita a conversão desnecessária para dobrar e evita preocupações de transbordamento, além de fornecer uma explicação clara.
ZX9
2
@IanNelson de maneira mais geral, se xfor divisível por y, y/x + 1seria muito alto.
Ohad Schneider
11
@ ZX9 Não, não evita preocupações com transbordamento. É exatamente a mesma solução que Ian Nelson postou aqui.
user247702
Respostas:
478
Encontrou uma solução elegante:
int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
-1 por causa do erro de estouro apontado por Brandon Durette
finnw
30
Sr. Óbvio diz: Lembre-se de certificar-se de que recordsPerPage não é zero
Adam Gent
7
Bom trabalho, não acredito que o C # não tenha teto inteiro.
gosukiwi
2
Sim, aqui estou eu, em meados de 2017, tropeçando nessa ótima resposta depois de tentar várias abordagens muito mais complexas.
Mifo 29/07
11
Para linguagens com um operador adequado da divisão euclidiana, como Python, uma abordagem ainda mais simples seria pageCount = -((-records) // recordsPerPage).
Supercat
194
Converter em ponto flutuante e vice-versa parece uma enorme perda de tempo no nível da CPU.
A solução de Ian Nelson:
int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
Pode ser simplificado para:
int pageCount =(records -1)/ recordsPerPage +1;
AFAICS, isso não tem o bug de estouro que Brandon DuRette apontou e, como o usa apenas uma vez, você não precisa armazenar o recordsPerPage especialmente se for de uma função cara para buscar o valor de um arquivo de configuração ou alguma coisa.
Ou seja, isso pode ser ineficiente, se config.fetch_value usou uma pesquisa no banco de dados ou algo assim:
int pageCount =(records + config.fetch_value('records per page')-1)/ config.fetch_value('records per page');
Isso cria uma variável que você realmente não precisa, que provavelmente tem implicações (menores) de memória e é muita digitação:
int recordsPerPage = config.fetch_value('records per page')int pageCount =(records + recordsPerPage -1)/ recordsPerPage;
Isso é tudo em uma linha e somente busca os dados uma vez:
int pageCount =(records -1)/ config.fetch_value('records per page')+1;
+1, a questão de zero registros ainda retornando 1 pageCount é realmente útil, pois eu ainda quero uma página, mostrando o espaço reservado / linha falsa de "nenhum registro corresponde aos seus critérios", ajuda a evitar problemas de "contagem de 0 páginas" controle de paginação que você usa.
Timothy Walters
27
Esteja ciente de que as duas soluções não retornam a mesma pageCount para zero registros. Esta versão simplificada retornará 1 pageCount para zero registros, enquanto a versão Roland Backhouse retorna 0 pageCount. Tudo bem se você deseja isso, mas as duas equações não são equivalentes quando executadas pela divisão inteira no estilo C # / Java.
6606 Ian Nelson #
10
edição minúscula para maior clareza para as pessoas que escaneiam e faltam bodmas ao mudar para a simplificação da solução Nelson (como fiz na primeira vez!), a simplificação com colchetes é ... int pageCount = ((records - 1) / recordsPerPage) + 1;
Dave heywood
11
Você deve adicionar parênteses à versão simplificada para que ela não dependa de uma ordem específica de operações. ou seja, ((records - 1) / recordsPerPage) + 1. #
Martin
11
@Ian, esta resposta nem sempre retorna 1. Ele pode retornar 0 se o seu recordsPerPage é "1" e há 0 registos: -1 / 1 + 1 = 0. Embora essa não seja uma ocorrência super comum, é importante ter em mente se você está permitindo que os usuários ajustem o tamanho da página. Portanto, não permita que os usuários tenham um tamanho de página igual a 1, verifique o tamanho da página ou ambos (provavelmente preferível para evitar comportamentos inesperados).
Michael
81
Para C #, a solução é converter os valores em um dobro (como Math.Ceiling recebe um dobro):
int nPages =(int)Math.Ceiling((double)nItems /(double)nItemsPerPage);
Em java, você deve fazer o mesmo com Math.ceil ().
por que essa resposta está tão distante quando o op pede explicitamente c #!
Felickz 01/10/12
2
Você também precisa converter a saída para, intporque Math.Ceilingretorna a doubleou decimal, dependendo dos tipos de entrada.
DanM7
14
porque é extremamente ineficiente
Zar Shardan
6
Pode ser ineficiente, mas é extremamente fácil de entender. Dado que o cálculo de uma contagem de páginas geralmente é feito uma vez por solicitação, qualquer perda de desempenho não seria mensurável.
Jared Kells
11
É pouco mais legível do que isso "(dividendo + (divisor - 1)) / divisor;" também é lento e requer a biblioteca de matemática.
rolos
68
Isso deve dar o que você deseja. Você definitivamente desejará x itens divididos por y itens por página, o problema é quando números desiguais aparecem, portanto, se houver uma página parcial, também queremos adicionar uma página.
int x = number_of_items;int y = items_per_page;// with out libraryint pages = x/y +(x % y >0?1:0)// with libraryint pages =(int)Math.Ceiling((double)x /(double)y);
x / y + !! (x% y) evita a ramificação para idiomas do tipo C. As probabilidades são boas, no entanto, seu compilador está fazendo isso de qualquer maneira.
Rhys Ulerich
2
+1 por não estourar como as respostas acima ... embora converter ints para dobras apenas para Math.ceiling e depois voltar novamente é uma má ideia no código sensível ao desempenho.
Cogwheel
3
@RhysUlerich que não funciona em c # (não pode converter diretamente um int em um bool). A solução de rjmunro é a única maneira de evitar ramificações, eu acho.
Smead
18
A solução matemática inteira fornecida por Ian é boa, mas sofre de um erro de estouro inteiro. Supondo que as variáveis sejam todas int, a solução pode ser reescrita para usar a longmatemática e evitar o erro:
int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
Se recordsfor um long, o bug permanece. A solução do módulo não possui o erro.
@finnw: AFAICS, não há um exemplo do mundo real nessa página, apenas um relatório de alguém encontrando o bug em um cenário teórico.
Rjmunro
5
Sim, eu estava sendo pedante ao apontar o bug. Muitos bugs podem existir perpetuamente sem nunca causar problemas. Um bug da mesma forma existia na implementação do binarySearch pelo JDK por nove anos, antes que alguém o denunciasse ( googleresearch.blogspot.com/2006/06/… ). Acho que a pergunta é, independentemente de quão improvável você encontre esse bug, por que não corrigi-lo com antecedência?
Brandon Durette
4
Além disso, deve-se notar que não é apenas o número de elementos paginados que importa, mas também o tamanho da página. Portanto, se você estiver construindo uma biblioteca e alguém optar por não paginar passando 2 ^ 31-1 (Integer.MAX_VALUE) como o tamanho da página, o bug será acionado.
int q = records / recordsPerPage, r = records % recordsPerPage;int pageCount = q -(-r >>(Integer.SIZE -1));
Nota: (-r >> (Integer.SIZE - 1))consiste no bit de sinal rrepetido 32 vezes (graças à extensão do sinal do >>operador.) Avalia como 0 se rfor zero ou negativo, -1 se rfor positivo. Portanto, subtraí-lo qtem o efeito de adicionar 1 se records % recordsPerPage > 0.
Para registros == 0, a solução de rjmunro fornece 1. A solução correta é 0. Dito isto, se você souber que registros> 0 (e tenho certeza de que todos assumimos recordsPerPage> 0), a solução rjmunro fornece resultados corretos e não possui nenhum dos problemas de estouro.
int pageCount =0;if(records >0){
pageCount =(((records -1)/ recordsPerPage)+1);}// no else required
Todas as soluções matemáticas inteiras serão mais eficientes do que qualquer uma das soluções de ponto flutuante.
Nenhuma verificação aqui (excesso, DivideByZeroetc), fique à vontade para adicionar se quiser. A propósito, para aqueles preocupados com a sobrecarga de chamada de método, funções simples como essa podem ser incorporadas pelo compilador de qualquer maneira, então não acho que seja esse o motivo. Felicidades.
PS: você pode achar útil também estar ciente disso (fica o restante):
int remainder;int result =Math.DivRem(dividend, divisor,out remainder);
Isto está incorreto. Por exemplo: DivideUp(4, -2)retorna 0 (deve ser -2). É correto apenas para números inteiros não negativos que não são claros na resposta ou na interface da função.
Thash
6
Thash, por que você não faz algo útil como adicionar a pequena verificação extra, se o número for negativo, em vez de votar minha resposta para baixo e fazer incorretamente a declaração geral: "Isso está incorreto", quando na verdade é apenas uma vantagem caso. Eu já deixei claro que você deve fazer outras verificações primeiro: "Nenhuma verificação aqui (estouro, DivideByZero, etc), fique à vontade para adicionar se quiser ."
Nicholas Petersen
11
A pergunta mencionada "Estou pensando em particular em como exibir controles de paginação " para que números negativos estivessem fora dos limites de qualquer maneira. Novamente, basta fazer algo útil e sugerir uma verificação adicional, se você quiser, é um homem de esforço em equipe.
Nicholas Petersen
Eu não quis ser rude e me desculpe se você entender dessa maneira. A questão era "Como arredondar o resultado da divisão inteira". O autor mencionou a paginação, mas outras pessoas podem ter necessidades diferentes. Eu acho que seria melhor se sua função refletisse de alguma forma que ela não funciona para números inteiros negativos, uma vez que não está claro na interface (por exemplo, um nome ou tipo de argumento diferente). Para trabalhar com números inteiros negativos, você pode, por exemplo, pegar um valor absoluto do dividendo e do divisor e multiplicar o resultado pelo seu sinal.
Thash
2
Outra alternativa é usar a função mod () (ou '%'). Se houver um restante diferente de zero, aumente o resultado inteiro da divisão.
O seguinte deve fazer o arredondamento melhor do que as soluções acima, mas à custa do desempenho (devido ao cálculo do ponto flutuante de 0,5 * rctDenominator):
uint64_t integerDivide(constuint64_t& rctNumerator,constuint64_t& rctDenominator ){// Ensure .5 upwards is rounded up (otherwise integer division just truncates - ie gives no remainder)return(rctDenominator ==0)?0:(rctNumerator +(int)(0.5*rctDenominator))/ rctDenominator;}
x
for divisível pory
,y/x + 1
seria muito alto.Respostas:
Encontrou uma solução elegante:
Fonte: Conversão de números, Roland Backhouse, 2001
fonte
pageCount = -((-records) // recordsPerPage)
.Converter em ponto flutuante e vice-versa parece uma enorme perda de tempo no nível da CPU.
A solução de Ian Nelson:
Pode ser simplificado para:
AFAICS, isso não tem o bug de estouro que Brandon DuRette apontou e, como o usa apenas uma vez, você não precisa armazenar o recordsPerPage especialmente se for de uma função cara para buscar o valor de um arquivo de configuração ou alguma coisa.
Ou seja, isso pode ser ineficiente, se config.fetch_value usou uma pesquisa no banco de dados ou algo assim:
Isso cria uma variável que você realmente não precisa, que provavelmente tem implicações (menores) de memória e é muita digitação:
Isso é tudo em uma linha e somente busca os dados uma vez:
fonte
-1 / 1 + 1 = 0
. Embora essa não seja uma ocorrência super comum, é importante ter em mente se você está permitindo que os usuários ajustem o tamanho da página. Portanto, não permita que os usuários tenham um tamanho de página igual a 1, verifique o tamanho da página ou ambos (provavelmente preferível para evitar comportamentos inesperados).Para C #, a solução é converter os valores em um dobro (como Math.Ceiling recebe um dobro):
Em java, você deve fazer o mesmo com Math.ceil ().
fonte
int
porqueMath.Ceiling
retorna adouble
oudecimal
, dependendo dos tipos de entrada.Isso deve dar o que você deseja. Você definitivamente desejará x itens divididos por y itens por página, o problema é quando números desiguais aparecem, portanto, se houver uma página parcial, também queremos adicionar uma página.
fonte
A solução matemática inteira fornecida por Ian é boa, mas sofre de um erro de estouro inteiro. Supondo que as variáveis sejam todas
int
, a solução pode ser reescrita para usar along
matemática e evitar o erro:int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;
Se
records
for umlong
, o bug permanece. A solução do módulo não possui o erro.fonte
Uma variante da resposta de Nick Berardi que evita um ramo:
Nota:
(-r >> (Integer.SIZE - 1))
consiste no bit de sinalr
repetido 32 vezes (graças à extensão do sinal do>>
operador.) Avalia como 0 ser
for zero ou negativo, -1 ser
for positivo. Portanto, subtraí-loq
tem o efeito de adicionar 1 serecords % recordsPerPage > 0
.fonte
Para registros == 0, a solução de rjmunro fornece 1. A solução correta é 0. Dito isto, se você souber que registros> 0 (e tenho certeza de que todos assumimos recordsPerPage> 0), a solução rjmunro fornece resultados corretos e não possui nenhum dos problemas de estouro.
Todas as soluções matemáticas inteiras serão mais eficientes do que qualquer uma das soluções de ponto flutuante.
fonte
Na necessidade de um método de extensão:
Nenhuma verificação aqui (excesso,
DivideByZero
etc), fique à vontade para adicionar se quiser. A propósito, para aqueles preocupados com a sobrecarga de chamada de método, funções simples como essa podem ser incorporadas pelo compilador de qualquer maneira, então não acho que seja esse o motivo. Felicidades.PS: você pode achar útil também estar ciente disso (fica o restante):
fonte
DivideUp(4, -2)
retorna 0 (deve ser -2). É correto apenas para números inteiros não negativos que não são claros na resposta ou na interface da função.Outra alternativa é usar a função mod () (ou '%'). Se houver um restante diferente de zero, aumente o resultado inteiro da divisão.
fonte
Eu faço o seguinte, lida com qualquer excesso:
E use esta extensão para se houver 0 resultado:
Além disso, para o número da página atual (não foi solicitado, mas pode ser útil):
fonte
Alternativa para remover ramificação no teste para zero:
Não tenho certeza se isso funcionará em C #, deve funcionar em C / C ++.
fonte
Um método genérico, cujo resultado você pode repetir pode ser interessante:
fonte
Lists.partition(List, int)
) e, ironicamente, osize()
método resultanteList
(a partir der09
) sofre do bug de estouro mencionado na resposta de Brandon DuRette .Eu tinha uma necessidade semelhante em que precisava converter Minutos em horas e minutos. O que eu usei foi:
fonte
O seguinte deve fazer o arredondamento melhor do que as soluções acima, mas à custa do desempenho (devido ao cálculo do ponto flutuante de 0,5 * rctDenominator):
fonte
Você deseja fazer a divisão de ponto flutuante e, em seguida, usar a função de teto, para arredondar o valor para o próximo número inteiro.
fonte