При заданных целочисленных значениях x
и y
C, и C ++ оба возвращают как частное q = x/y
значение эквивалента с плавающей запятой. Меня интересует метод возврата потолка. Например, ceil(10/5)=2
и ceil(11/5)=3
.
Очевидный подход включает в себя что-то вроде:
q = x / y;
if (q * y < x) ++q;
Это требует дополнительного сравнения и умножения; и другие методы, которые я видел (использовал на самом деле), включают приведение в качестве float
или double
. Есть ли более прямой метод, который избегает дополнительного умножения (или второго деления) и ветвления, и который также избегает приведения к числу с плавающей запятой?
q = x/y + (x % y != 0);
достаточноОтветы:
Для положительных чисел
Чтобы округлить ...
или (избегая переполнения в x + y)
источник
x/y
как и потолок деления. В C90 не указано, как округлять, и я не думаю, что текущий стандарт C ++ также делает.q = x / y;
Для положительных чисел:
источник
Ответ Спарки - это один из стандартных способов решения этой проблемы, но, как я уже писал в своем комментарии, вы рискуете переполниться. Это можно решить, используя более широкий тип, но что, если вы хотите разделить
long long
s?Ответ Натана Эрнста дает одно решение, но оно включает вызов функции, объявление переменной и условие, что делает его не короче кода OP и, возможно, даже медленнее, поскольку его сложнее оптимизировать.
Мое решение таково:
Это будет немного быстрее, чем код OP, потому что по модулю и делению выполняется одна и та же инструкция на процессоре, потому что компилятор может видеть, что они эквивалентны. По крайней мере, gcc 4.4.1 выполняет эту оптимизацию с флагом -O2 на x86.
Теоретически, компилятор может встроить вызов функции в код Натана Эрнста и выдать то же самое, но gcc не сделал этого, когда я тестировал его. Это может быть связано с тем, что скомпилированный код будет привязан к одной версии стандартной библиотеки.
В заключение отметим, что на современном компьютере все это не имеет значения, за исключением случаев, когда вы находитесь в чрезвычайно узком цикле и все ваши данные находятся в регистрах или L1-кэше. В противном случае все эти решения будут одинаково быстрыми, за исключением, возможно, решения Натана Эрнста, которое может быть значительно медленнее, если функция должна быть извлечена из основной памяти.
источник
q = (x > 0)? 1 + (x - 1)/y: (x / y);
q = x / y + (x % y > 0);
это легче, чем? :
выражение?Вы можете использовать
div
функцию в cstdlib, чтобы получить частное и остаток в одном вызове, а затем обрабатывать потолок отдельно, как показано нижеисточник
return res.quot + !!res.rem;
:)Как насчет этого? (требует, чтобы y было неотрицательным, поэтому не используйте его в редком случае, когда y - переменная без гарантии неотрицательности)
Я сократил
y/y
до одного, исключив терминx + y - 1
и , тем самым, шанс переполнения.Я избегаю
x - 1
обтекания, когдаx
тип без знака и содержит ноль.Для знаковых
x
отрицательный и ноль все еще объединяются в один случай.Вероятно, это не большое преимущество для современного процессора общего назначения, но это будет намного быстрее во встроенной системе, чем любой другой правильный ответ.
источник
Существует решение как для положительного, так и для отрицательного,
x
но только для положительногоy
только с 1 делением и без ветвейОбратите внимание: если
x
положительное значение, то деление стремится к нулю, и мы должны добавить 1, если напоминание не равно нулю.Если
x
отрицательно, то деление к нулю, это то, что нам нужно, и мы не будем ничего добавлять, потому чтоx % y
это не положительноисточник
Это работает для положительных или отрицательных чисел:
Если есть остаток, проверяет, если
x
иy
имеют тот же знак и добавляет1
соответственно.источник
Я бы скорее прокомментировал, но у меня недостаточно высокая репутация.
Насколько мне известно, для положительных аргументов и делителя, который является степенью 2, это самый быстрый способ (проверено в CUDA):
Только для общих положительных аргументов, я склонен делать это так:
источник
q = x/y + !!(x % y);
складываютсяq = x/y + (x % y == 0);
иq = (x + y - 1) / y;
решения с точки зрения производительности в современной CUDA.упрощенная общая форма,
Для более общего ответа функции C ++ для целочисленного деления с четко определенной стратегией округления
источник
Компилировать с O3, Компилятор хорошо выполняет оптимизацию.
источник