Ответ 1
Как сказано выше, вы должны сделать умножение перед делением. В любом случае вы можете написать свое выражение с помощью только делителя:
int height2 = (int)Math.Round(width2 * (height1 / (float)width1));
Мне нужен результат уравнения, округленного до ближайшего целого. например
137 * (3/4) = 103
Рассмотрим следующий неверный код.
int width1 = 4;
int height1 = 3;
int width2 = 137;
int height2 = width2 * (height1 / width1);
Каков правильный способ выполнения математики "целочисленный" в С#?
Мне действительно нужно делать:
int height2 = (int)Math.Round(
(float)width2 * ((float)height1 / (float)width1)
);
Как сказано выше, вы должны сделать умножение перед делением. В любом случае вы можете написать свое выражение с помощью только делителя:
int height2 = (int)Math.Round(width2 * (height1 / (float)width1));
int height2 = (width2 * height1) / width1;
Сначала выполните умножение (пока они не будут переполняться) и второй раздел.
3/4 == 0 в целочисленной математике (целочисленная математика не округляется по делению, она обрезается).
Если вам действительно нужно округление, вам нужно либо работать в неподвижной точке, с плавающей запятой, либо играть с модулем.
Я думаю, что это самый элегантный способ сделать это:
Math.round(myinteger * 0.75);
Использование 0.75 вместо 3/4 будет неявно использовать его для double/float и почему бы не использовать функции по умолчанию, которые предоставляются для этого?
Я исправлю неправильный код, добавив нулевые строки кода:
float width1 = 4;
float height1 = 3;
float width2 = 137;
float height2 = width2 * (height1 / width1);
Вы должны использовать float для переменных, которые могут содержать десятичные числа. Это включает в себя высоты, рассчитанные по коэффициентам. Вы можете всегда отбрасывать int позже, если это проблема.
Никогда не бросать в float, он имеет даже меньшую точность, чем 32-битное целое число. Если вы собираетесь использовать плавающие точки, всегда используйте double вместо float.
Просто наткнулся на этот вопрос. Ответ Аарона кажется мне почти правильным. Но я уверен, что вам нужно указать middlepointrounding, если ваша проблема является проблемой "реального мира". Поэтому мой ответ, основанный на коде Аарона,
int height2 = (int)Math.Round(width2 * (height1 / (float)width1),MidpointRounding.AwayFromZero);
Чтобы увидеть разницу, запустите этот код в консоли
Console.WriteLine((int)Math.Round(0.5));
Console.WriteLine((int)Math.Round(1.5));
Console.WriteLine((int)Math.Round(2.5));
Console.WriteLine((int)Math.Round(3.5));
Console.WriteLine((int)Math.Round(0.5, MidpointRounding.AwayFromZero));
Console.WriteLine((int)Math.Round(1.5, MidpointRounding.AwayFromZero));
Console.WriteLine((int)Math.Round(2.5, MidpointRounding.AwayFromZero));
Console.WriteLine((int)Math.Round(3.5, MidpointRounding.AwayFromZero));
Console.ReadLine();
Подробнее вы можете найти в этой статье.
Шесть лет (округленный) позже, здесь мой вклад - небольшой трюк, который я узнал давно, и удивляюсь, что здесь никто не упомянул.
Идея состоит в том, чтобы округлить, добавив половину делителя к числителю, прежде чем делать деление.
int height2 = (width2 * height1 + width1 / 2) / width1;
В действительности я бы не стал рекомендовать это делать в случаях, подобных OP, где делитель является переменной. Вместо этого лучше использовать Math.Round(), поскольку это намного легче понять.
Но в тех случаях, когда делитель является константой, я использую этот трюк. Поэтому вместо
int height2 = width2 * height1 / 4; // No rounding
Я бы использовал
int height2 = (width2 * height1 + 2) / 4;
Здесь более типичный пример
private static Size ResizeWithPercentage(Size oldSize, int resizePercentage)
{
return new Size((oldSize.Width * resizePercentage + 50) / 100,
(oldSize.Height * resizePercentage + 50) / 100);
}
Другая возможность состоит в том, чтобы объединить этот трюк с идеей, упомянутой dongilmore и supercat, что вместо того, чтобы иметь деление на два указанных или подразумеваемых, вы можете умножить числитель и знаменатель на два.
int height2 = (width2 * height1 * 2 + width1) / (width1 * 2);
Это дает лучшие ответы в тех случаях, когда делитель является или может быть нечетным числом.
Разработайте сообщение Джеффри, поскольку у вас обычно больше шансов усеченных нужных десятичных дробей, чем у вас есть переполнение 32-битного целого числа (а также потому, что умножение и деление являются коммутативными), вы обычно должны делать умножение перед делением.
int height2 = ((width2 * height1 * 10) + 5) / (width1 * 10);
До любого целочисленного деления убедитесь, что делитель не равен нулю. Также обратите внимание, что это предполагает положительный коэффициент. Если отрицательный, округление должно быть -5, а не +5.
Преобразование конверсий всегда округляется так:
int height2 = Convert.ToInt32(width2 * height1 / (double)width1);
Достаточно эффективный подход, если окончательное деление будет равно четному числу, и результат всегда будет положительным, так это разделить на половину этого значения, добавить одно и разделить на два. Если результат может быть отрицательным, вы должны, если возможно, добавить сумму, которая сделает все положительной, сделайте вычисление, а затем вычтите соответствующую сумму позже.
Если окончательное деление будет нечетным числом, умножьте и числитель, и знаменатель на 2, затем действуйте так, как указано выше. Например, чтобы вычислить * 5/7, округлить, вычислить (a*10+1)>>1
. Единственное, на что нужно обратить внимание, это то, что вам может потребоваться расширить ваши значения до более крупного числового типа, чтобы избежать переполнения или, если это невозможно, разделить деление на части. Например, для вычисления a * 14/15 вы можете вычислить ((a * 4/3 * 7)/5 + 1)/2. Это вычисление может все еще переполняться, если оно слишком велико, но допустимый диапазон будет в три раза больше, чем если бы он был оценен без деления на 3 перед другим делением. Обратите внимание, что разделение операции сделает округление немного менее точным, но все же достаточно близким для многих целей.