Сведения о вопросе

1234123213

07:34, 13th August, 2020

Теги

c#   java   math    

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

Просмотров: 449   Ответов: 16

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

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



  Сведения об ответе

PIRLO

20:27, 21st August, 2020

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

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

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


  Сведения об ответе

DAAA

18:42, 28th August, 2020

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

Решение Иэн Нельсон :

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

Можно упростить до:

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

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

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


  Сведения об ответе

прога

13:40, 3rd August, 2020

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

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

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


  Сведения об ответе

padenie

23:24, 26th August, 2020

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


  Сведения об ответе

VERSUION

11:28, 14th August, 2020

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

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

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


  Сведения об ответе

PIRLO

09:35, 23rd August, 2020

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

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 .


  Сведения об ответе

JUST___

13:12, 21st August, 2020

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

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

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


  Сведения об ответе

screen

21:06, 1st October, 2020

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

    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);


  Сведения об ответе

DINO

15:16, 20th August, 2020

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


  Сведения об ответе

LAST

14:28, 10th August, 2020

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

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;


  Сведения об ответе

PIRLO

11:50, 17th August, 2020

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

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

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


  Сведения об ответе

DO__IT

22:38, 10th August, 2020

для C# используйте функцию Math.Ceiling:

var pageCount= Math.Ceiling((double)myList.Count() / recordsPerPage);

и Java использовать функцию Math.Ceil:

int n = (int) Math.ceil((double)myList.size() / recordsPerPage));


  Сведения об ответе

SKY

20:00, 20th August, 2020

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

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;
}


  Сведения об ответе

park

14:48, 11th August, 2020

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

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);


  Сведения об ответе

PROGA

10:10, 12th August, 2020

Следующее должно делать округление лучше, чем вышеприведенные решения, но за счет производительности (за счет вычисления с плавающей точкой 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;
}


  Сведения об ответе

LAST

02:36, 6th August, 2020

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться