Окончательный int-based ответ
Для целых чисел со знаком:
int div = a / b;
if (((a ^ b) >= 0) && (a % b != 0))
div++;
Для целых чисел без знака:
int div = a / b;
if (a % b != 0)
div++;
Обоснование этого ответа
Целочисленное деление '/
' определено для округления до нуля (7.7.2 спецификации), но мы хотим округлить в большую сторону. Это означает, что отрицательные ответы уже округлены правильно, но положительные ответы необходимо скорректировать.
Нулевые положительные ответы легко обнаружить, но нулевой ответ немного сложнее, поскольку это может быть либо округление отрицательного значения, либо округление положительного.
Самая безопасная ставка - определить, когда ответ должен быть положительным, проверив, что знаки обоих целых совпадают. Целочисленный оператор xor '^
' для этих двух значений приведет к появлению 0-значного бита, если это так, что означает неотрицательный результат, поэтому проверка (a ^ b) >= 0
определяет, что результат должен быть положительным до округления. Также обратите внимание, что для целых чисел без знака каждый ответ явно положительный, поэтому эту проверку можно опустить.
Тогда остается только проверить, произошло ли какое-либо округление, для которого a % b != 0
выполнит работу.
Извлеченные уроки
Арифметика (целочисленная или иная) не так проста, как кажется. Всегда нужно тщательно обдумывать.
Кроме того, хотя мой окончательный ответ, возможно, не такой «простой» или «очевидный» или, возможно, даже «быстрый», как ответы с плавающей запятой, у меня есть одно очень сильное искупительное качество для меня; Теперь я обдумал ответ, поэтому я уверен, что он правильный (пока кто-нибудь умнее не скажет мне иначе - украдкой взгляд в сторону Эрика -).
Чтобы получить такое же чувство уверенности в ответе с плавающей запятой, мне нужно было бы сделать больше (и, возможно, более сложно) подумать о том, существуют ли какие-либо условия, при которых точность с плавающей запятой может мешать, и Math.Ceiling
возможно делает что-то нежелательное на "правильных" входах.
пройденный путь
Заменить (заметьте, я заменил второе myInt1
на myInt2
, предполагая, что это то, что вы имели в виду):
(int)Math.Ceiling((double)myInt1 / myInt2)
с:
(myInt1 - 1 + myInt2) / myInt2
Единственное предостережение в том, что если myInt1 - 1 + myInt2
переполняет целочисленный тип, который вы используете, вы можете не получить то, что ожидаете.
Причина, по которой это неправильно : -1000000 и 3999 должны дать -250, это дает -249
EDIT:
Учитывая, что это имеет ту же ошибку, что и другое целочисленное решение для отрицательных значений myInt1
, может быть проще сделать что-то вроде:
int rem;
int div = Math.DivRem(myInt1, myInt2, out rem);
if (rem > 0)
div++;
Это должно дать правильный результат в div
, используя только целочисленные операции.
Причина, по которой это неправильно : -1 и -5 должны давать 1, это дает 0
РЕДАКТИРОВАТЬ (еще раз, с чувством):
Оператор деления округляется до нуля; для отрицательных результатов это совершенно верно, поэтому только неотрицательные результаты требуют корректировки. Также учитывая, что DivRem
просто выполняет /
и %
в любом случае, давайте пропустим вызов (и начнем с простого сравнения, чтобы избежать вычисления по модулю, когда оно не нужно):
int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
div++;
Причина, по которой это неправильно : -1 и 5 должны давать 0, это дает 1
(Защищая последнюю попытку, я никогда не должен был пытаться дать обоснованный ответ, пока мой разум говорил мне, что я на 2 часа опоздал на сон)