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

голоса
269

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

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

Задан 20/08/2008 в 14:27
источник пользователем
На других языках...                            


15 ответов

голоса
405

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

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

Источник: Number Conversion, Roland Backhouse, 2001

Ответил 20/08/2008 в 14:42
источник пользователем

голоса
162

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

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

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

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

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

AFAICS, это не имеет переполнение ошибки, Brandon DuRette указал, и потому, что он использует только один раз, вам не нужно хранить 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;
Ответил 02/02/2009 в 14:26
источник пользователем

голоса
56

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

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);
Ответил 20/08/2008 в 14:31
источник пользователем

голоса
51

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

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

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

Ответил 20/08/2008 в 14:33
источник пользователем

голоса
15

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

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

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

Ответил 18/09/2008 в 22:01
источник пользователем

голоса
6

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

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.

Ответил 04/05/2011 в 14:00
источник пользователем

голоса
4

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

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

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

Ответил 11/02/2009 в 11:18
источник пользователем

голоса
3

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

    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);
Ответил 15/09/2016 в 19:52
источник пользователем

голоса
2

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

Ответил 20/08/2008 в 14:30
источник пользователем

голоса
1

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

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;
Ответил 04/02/2014 в 10:36
источник пользователем

голоса
0

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

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

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

Ответил 13/08/2010 в 04:26
источник пользователем

голоса
-1

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

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<numChunks; i++) {
        dest[i] = new Object[ (i<numChunks-1 || overflow==0) ? chunkSize : overflow ];
        System.arraycopy(src, i*chunkSize, dest[i], 0, dest[i].length); 
    }
    return dest;
}
Ответил 28/10/2010 в 15:09
источник пользователем

голоса
-2

Ниже следует делать округления лучше, чем выше решений, но в ущерб производительности (за счет вычисления с плавающей точкой 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;
}
Ответил 07/02/2013 в 16:02
источник пользователем

голоса
-2

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

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);
Ответил 19/03/2012 в 14:47
источник пользователем

голоса
-4

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

Ответил 20/08/2008 в 14:29
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more