Подтвердить что ты не робот

С#: Как сделать простую математику с округлением по целым числам?

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

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

Ответ 1

Как сказано выше, вы должны сделать умножение перед делением. В любом случае вы можете написать свое выражение с помощью только делителя:

int height2 = (int)Math.Round(width2 * (height1 / (float)width1));

Ответ 2

int height2 = (width2 * height1) / width1;

Ответ 3

Сначала выполните умножение (пока они не будут переполняться) и второй раздел.

3/4 == 0 в целочисленной математике (целочисленная математика не округляется по делению, она обрезается).

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

Ответ 4

Я думаю, что это самый элегантный способ сделать это:

Math.round(myinteger * 0.75);

Использование 0.75 вместо 3/4 будет неявно использовать его для double/float и почему бы не использовать функции по умолчанию, которые предоставляются для этого?

Ответ 5

Я исправлю неправильный код, добавив нулевые строки кода:

float width1 = 4;
float height1 = 3;

float width2 = 137;
float height2 = width2 * (height1 / width1);

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

Ответ 6

Никогда не бросать в float, он имеет даже меньшую точность, чем 32-битное целое число. Если вы собираетесь использовать плавающие точки, всегда используйте double вместо float.

Ответ 7

Просто наткнулся на этот вопрос. Ответ Аарона кажется мне почти правильным. Но я уверен, что вам нужно указать 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();

Подробнее вы можете найти в этой статье.

Ответ 8

Шесть лет (округленный) позже, здесь мой вклад - небольшой трюк, который я узнал давно, и удивляюсь, что здесь никто не упомянул.

Идея состоит в том, чтобы округлить, добавив половину делителя к числителю, прежде чем делать деление.

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

Это дает лучшие ответы в тех случаях, когда делитель является или может быть нечетным числом.

Ответ 9

Разработайте сообщение Джеффри, поскольку у вас обычно больше шансов усеченных нужных десятичных дробей, чем у вас есть переполнение 32-битного целого числа (а также потому, что умножение и деление являются коммутативными), вы обычно должны делать умножение перед делением.

Ответ 10

int height2 = ((width2 * height1 * 10) + 5) / (width1 * 10);

До любого целочисленного деления убедитесь, что делитель не равен нулю. Также обратите внимание, что это предполагает положительный коэффициент. Если отрицательный, округление должно быть -5, а не +5.

Ответ 11

Преобразование конверсий всегда округляется так:

int height2 = Convert.ToInt32(width2 * height1 / (double)width1);

Ответ 12

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

Если окончательное деление будет нечетным числом, умножьте и числитель, и знаменатель на 2, затем действуйте так, как указано выше. Например, чтобы вычислить * 5/7, округлить, вычислить (a*10+1)>>1. Единственное, на что нужно обратить внимание, это то, что вам может потребоваться расширить ваши значения до более крупного числового типа, чтобы избежать переполнения или, если это невозможно, разделить деление на части. Например, для вычисления a * 14/15 вы можете вычислить ((a * 4/3 * 7)/5 + 1)/2. Это вычисление может все еще переполняться, если оно слишком велико, но допустимый диапазон будет в три раза больше, чем если бы он был оценен без деления на 3 перед другим делением. Обратите внимание, что разделение операции сделает округление немного менее точным, но все же достаточно близким для многих целей.