简体   繁体   English

C#:如何使用舍入对整数进行简单的数学运算?

[英]C#: How do I do simple math, with rounding, on integers?

i want the result of an equation rounded to the nearest integer. 我希望方程的结果四舍五入到最接近的整数。 eg 例如

137 * (3/4) = 103

Consider the following incorrect code. 请考虑以下错误代码。

int width1 = 4;
int height1 = 3;

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

What is the proper way to perform "integer" math in C#? 在C#中执行“整数”数学的正确方法是什么?

Do i really have to do: 我真的必须这样做:

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

As said above, you should do the multiplication before the division. 如上所述,你应该在除法之前进行乘法运算。 Anyway you could write your expression with casting only the divisor: 无论如何,你可以只使用除数来编写你的表达式:

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

Do multiplication first (as long as they're not likely to overflow) and division second. 首先进行乘法(只要它们不可能溢出)和第二次除法。

3/4 == 0 in integer math (integer math doesn't round on division, it truncates). 整数数学中的3/4 == 0(整数数学不会在除法上舍入,它会截断)。

If you really need rounding, you have to either work in fixed point, floating point, or play around with the modulus. 如果你真的需要舍入,你必须在固定点,浮点或模数周围工作。

I think this is the most elegant way to do this: 我认为这是最优雅的方式:

Math.round(myinteger * 0.75);

Using 0.75 instead of 3/4 will implicitly cast it to an double/float and why not use the default functions that are provided for this? 使用0.75而不是3/4将隐式地将其转换为double / float,为什么不使用为此提供的默认函数?

Just stumbled upon this question. 只是偶然发现了这个问题。 Aaron's answer seems almost right to me. 亚伦的回答对我来说似乎是对的。 But I'm very sure you need to specify midpointrounding if your problem is a "real world" problem. 但我非常确定如果您的问题是“现实世界”问题,则需要指定midpointrounding。 So my answer, based on Aaron's code, is 所以根据Aaron的代码我的回答是

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

To see the difference run that code in console 要查看差异在控制台中运行该代码

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

For details you may look at this article. 有关详情可看文章。

Six years (rounded) later, here's my contribution - a little trick I learned long ago, and am surprised that nobody else has mentioned here. 六年(四舍五入)之后,这是我的贡献 - 我很久以前学到的一个小技巧,并且很惊讶没有其他人在这里提到过。

The idea is to do rounding by adding half of the divisor to the numerator before doing the division. 这个想法是在进行除法之前通过将一半除数加到分子来进行舍入。

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

In reality I wouldn't necessarily recommend doing that in cases, like the OP's, where the divisor is a variable. 实际上,我不一定会建议在例如OP的情况下执行此操作,其中除数是变量。 Instead it may be better to use Math.Round(), as it's much easier to understand. 相反,使用Math.Round()可能更好,因为它更容易理解。

But in cases where the divisor is a constant I do use this trick. 但是在除数是常数的情况下我会使用这个技巧。 So instead of 而不是

    int height2 = width2 * height1 / 4;  // No rounding

I'd use 我用了

    int height2 = (width2 * height1 + 2) / 4;

Here's a more typical example 这是一个更典型的例子

  private static Size ResizeWithPercentage(Size oldSize, int resizePercentage)
  {
     return new Size((oldSize.Width * resizePercentage + 50) / 100, 
                     (oldSize.Height * resizePercentage + 50) / 100);
  }

Another possibility is to combine this trick with the idea mentioned by dongilmore and supercat that instead of having a division by two specified or implied, you can multiply both the numerator and denominator by two. 另一种可能性是将这个技巧与dongilmore和supercat提到的想法结合起来,你可以将分子和分母乘以2,而不是用指定或暗示的除法。

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

This gives better answers in cases where the divisor is, or may be, an odd number. 在除数是或可能是奇数的情况下,这给出了更好的答案。

I will fix the incorrect code by adding zero lines of code: 我将通过添加零行代码来修复错误的代码:

float width1 = 4;
float height1 = 3;

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

You should use floats for variables that can possibly contain decimals. 您应该对可能包含小数的变量使用浮点数。 This includes heights calculated from ratios. 这包括根据比率计算的高度。 You can always cast to int later if that is a problem. 如果这是一个问题,您可以随后转换为int。

Never cast to float, it has even less precision than a 32-bit integer. 从不转换为浮点数,它的精度甚至低于32位整数。 If you're going to use floating point, always use double instead of float. 如果您要使用浮点数,请始终使用double而不是float。

A reasonably effective approach if the final division will be by an even number and the result will always be positive is to divide by half that value, add one, and divide by two. 一个合理有效的方法,如果最终除法将是偶数,结果总是正数,则除以该值的一半,加1,除以2。 If the result may be negative, you should if possible add an amount that will make everything be positive, do the computation, and then subtract a corresponding amount afterward. 如果结果可能是负数,则应尽可能添加一个使所有内容都为正的量,进行计算,然后再减去相应的量。

If the final division will be by an odd number, multiply both numerator and denominator by 2, then proceed as above. 如果最终除法是奇数,则将分子和分母乘以2,然后按上述步骤进行。 For example, to compute a*5/7, rounded, compute (a*10+1)>>1 . 例如,要计算* 5/7,舍入,计算(a*10+1)>>1 The one thing to watch out for is that you may need to extend your values to a larger numeric type to avoid overflow or, if that isn't possible, subdivide the division into pieces. 需要注意的一件事是,您可能需要将值扩展为更大的数值类型以避免溢出,或者如果不可能,则将除法细分为多个部分。 For example, to compute a*14/15, you might compute ((a*4/3*7)/5+1)/2. 例如,要计算* 14/15,您可以计算((a * 4/3 * 7)/ 5 + 1)/ 2。 That computation may still overflow if a is too big, but the allowable range will be three times as big as if it was evaluated without doing the divide by 3 before the other division. 如果a太大,那么该计算可能仍会溢出,但允许范围将是在没有在另一个除法之前除以3的情况下进行评估的三倍。 Note that subdividing the operation will make the rounding slightly less precise, but still close enough for many purposes. 请注意,细分操作会使舍入略微精确,但仍然足够接近以达到很多目的。

详细说明了Jeffery的消息,因为你通常比截断32位整数(并且因为乘法和除法是可交换的)更有可能截断所需的小数,你通常应该在除法之前进行乘法运算。

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

Prior to any integer division, check to make certain the divisor is not zero. 在进行任何整数除法之前,请检查以确定除数不为零。 Also note this assumes positive quotient. 另请注意,这假定为正商。 If negative, roundoff needs to be -5, not +5. 如果是负数,则舍入需要为-5,而不是+5。

转换的转换总是如此:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM