Как округлить результат целочисленного деления?

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

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

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

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

Источник: преобразование числа, Роланд Бакхаус, 2001

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

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

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

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

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

AFAICS, у этого нет ошибки переполнения, о которой указал Brandon DuRette, и поскольку она использует ее только один раз, вам не нужно специально хранить файл recordPerPage, если он исходит из дорогостоящей функции для извлечения значения из файла конфигурации или что нибудь.

Т.е. это может быть неэффективно, если 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; 

Это должно дать вам то, что вы хотите. Вы определенно хотите, чтобы элементы 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); 

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

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

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

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

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

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

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

 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 .

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

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

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

При необходимости использования метода расширения:

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

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

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

  int remainder; int result = Math.DivRem(dividend, divisor, out remainder); 

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

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

 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; 

Альтернатива для удаления ветвления при тестировании на ноль:

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

Не уверен, что это будет работать на C #, нужно делать в C / C ++.

Может быть интересен общий метод, результат которого можно перебрать.

 public static Object[][] chunk(Object[] src, int chunkSize) { int overflow = src.length%chunkSize; int numChunks = (src.length/chunkSize) + (overflow>0?1:0); Object[][] dest = new Object[numChunks][]; for (int i=0; i 

У меня была аналогичная потребность, когда мне нужно было перевести Минуты в часы и минуты. То, что я использовал, было:

 int hrs = 0; int mins = 0; float tm = totalmins; if ( tm > 60 ) ( hrs = (int) (tm / 60); mins = (int) (tm - (hrs * 60)); System.out.println("Total time in Hours & Minutes = " + hrs + ":" + mins); 

Следующее должно делать округление лучше, чем вышеупомянутые решения, но за счет производительности (из-за вычисления с плавающей запятой 0.5 * rctDenominator):

 uint64_t integerDivide( const uint64_t& rctNumerator, const uint64_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; } 

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

  • Как я могу проверить, приведет ли перемножение двух чисел в Java к переполнению?
  • Почему C # не использует арифметическую проверку переполнения по умолчанию?
  • Поиск всех подмножеств множества
  • Random.Next возвращает всегда одинаковые значения
  • Оценить математическое выражение из строки с помощью VB
  • JavaScript% (modulo) дает отрицательный результат для отрицательных чисел
  • Создание математической библиотеки с использованием Generics в C #
  • Вычисляя расстояние между двумя точками, используя широту долготы, что я делаю неправильно?
  • Выполняет ли литье в int после std :: floor гарантированный правильный результат?
  • OpenSouce C / C ++ Математический синтаксический анализатор библиотеки
  • Поворот группы векторов
  • Давайте будем гением компьютера.