Как округлить результат целочисленного деления? - PullRequest
298 голосов
/ 20 августа 2008

В частности, я думаю о том, как отображать элементы управления разбиением на страницы при использовании такого языка, как C # или Java.

Если у меня есть x элементов, которые я хочу отображать кусками y на страницу, сколько страниц потребуется?

Ответы [ 16 ]

434 голосов
/ 20 августа 2008

Нашли элегантное решение:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Источник: Преобразование чисел, Roland Backhouse, 2001

178 голосов
/ 02 февраля 2009

Преобразование в плавающую точку и обратно кажется огромной тратой времени на уровне процессора.

Решение Яна Нельсона:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Может быть упрощено до:

int pageCount = (records - 1) / recordsPerPage + 1;

AFAICS, в нем нет ошибки переполнения, на которую указывал Брэндон Дуретт, и поскольку она использует ее только один раз, вам не нужно специально хранить recordsPerPage, если она исходит из дорогой функции для извлечения значения из Конфигурационный файл или что-то.

т.е. это может быть неэффективно, если config.fetch_value использует поиск в базе данных или что-то в этом роде:

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');

Это создает переменную, которая вам на самом деле не нужна, которая, вероятно, имеет (незначительные) последствия для памяти и просто слишком много печатает:

int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

Это все одна строка, и данные извлекаются только один раз:

int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
66 голосов
/ 20 августа 2008

Для C # решение состоит в приведении значений к двойному (поскольку Math.Ceiling принимает двойное):

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);

В Java вы должны сделать то же самое с Math.ceil ().

64 голосов
/ 20 августа 2008

Это должно дать вам то, что вы хотите. Вам определенно понадобится разделить x элементов на y элементов на странице, проблема в том, что появляются неровные числа, поэтому, если есть частичная страница, мы также хотим добавить одну страницу.

int x = number_of_items;
int y = items_per_page;

// with out library
int pages = x/y + (x % y > 0 ? 1 : 0)

// with library
int pages = (int)Math.Ceiling((double)x / (double)y);
18 голосов
/ 19 сентября 2008

Целочисленное математическое решение, которое предоставил Ян, хорошо, но страдает от ошибки переполнения целых чисел. Предполагая, что все переменные int, решение может быть переписано для использования long математики и избежания ошибки:

int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;

Если records является long, ошибка остается. В модульном решении нет ошибки.

7 голосов
/ 04 мая 2011

Вариант ответа Ника Берарди , который избегает ответвления:

int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));

Примечание: (-r >> (Integer.SIZE - 1)) состоит из знакового бита r, повторяется 32 раза (благодаря расширению знака оператора >>.) Это значение равно 0, если r равно нулю или отрицательно, -1, если r положительно. Таким образом, вычитание его из q приводит к добавлению 1, если records % recordsPerPage > 0.

4 голосов
/ 11 февраля 2009

Для записей == 0 решение rjmunro дает 1. Правильное решение равно 0. При этом, если вы знаете, что записи> 0 (и я уверен, что мы все предположили recordsPerPage> 0), то решение rjmunro дает правильные результаты и не имеют проблем с переполнением.

int pageCount = 0;
if (records > 0)
{
    pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required

Все целочисленные математические решения будут более эффективными, чем любые решений с плавающей запятой.

3 голосов
/ 15 сентября 2016

При необходимости метода расширения:

    public static int DivideUp(this int dividend, int divisor)
    {
        return (dividend + (divisor - 1)) / divisor;
    }

Здесь нет проверок (переполнение, DivideByZero и т. Д.), Не стесняйтесь добавлять, если хотите. Кстати, для тех, кто беспокоится о накладных расходах при вызове метода, такие простые функции могут быть встроены компилятором в любом случае, так что я не думаю, что это то, о чем стоит беспокоиться. Приветствия.

P.S. вам также может быть полезно знать об этом (он получает остаток):

    int remainder; 
    int result = Math.DivRem(dividend, divisor, out remainder);
2 голосов
/ 20 августа 2008

Другой альтернативой является использование функции mod () (или «%»). Если есть ненулевой остаток, то увеличиваем целочисленный результат деления.

1 голос
/ 04 февраля 2014

Я делаю следующее, обрабатывает любые переполнения:

var totalPages = totalResults.IsDivisble(recordsperpage) ? totalResults/(recordsperpage) : totalResults/(recordsperpage) + 1;

И используйте это расширение, если есть 0 результатов:

public static bool IsDivisble(this int x, int n)
{
           return (x%n) == 0;
}

Кроме того, для текущего номера страницы (не спрашивался, но мог бы быть полезным):

var currentPage = (int) Math.Ceiling(recordsperpage/(double) recordsperpage) + 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...