繁体   English   中英

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

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

我希望方程的结果四舍五入到最接近的整数。 例如

137 * (3/4) = 103

请考虑以下错误代码。

int width1 = 4;
int height1 = 3;

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

在C#中执行“整数”数学的正确方法是什么?

我真的必须这样做:

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,为什么不使用为此提供的默认函数?

只是偶然发现了这个问题。 亚伦的回答对我来说似乎是对的。 但我非常确定如果您的问题是“现实世界”问题,则需要指定midpointrounding。 所以根据Aaron的代码我的回答是

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提到的想法结合起来,你可以将分子和分母乘以2,而不是用指定或暗示的除法。

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

在除数是或可能是奇数的情况下,这给出了更好的答案。

我将通过添加零行代码来修复错误的代码:

float width1 = 4;
float height1 = 3;

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

您应该对可能包含小数的变量使用浮点数。 这包括根据比率计算的高度。 如果这是一个问题,您可以随后转换为int。

从不转换为浮点数,它的精度甚至低于32位整数。 如果您要使用浮点数,请始终使用double而不是float。

一个合理有效的方法,如果最终除法将是偶数,结果总是正数,则除以该值的一半,加1,除以2。 如果结果可能是负数,则应尽可能添加一个使所有内容都为正的量,进行计算,然后再减去相应的量。

如果最终除法是奇数,则将分子和分母乘以2,然后按上述步骤进行。 例如,要计算* 5/7,舍入,计算(a*10+1)>>1 需要注意的一件事是,您可能需要将值扩展为更大的数值类型以避免溢出,或者如果不可能,则将除法细分为多个部分。 例如,要计算* 14/15,您可以计算((a * 4/3 * 7)/ 5 + 1)/ 2。 如果a太大,那么该计算可能仍会溢出,但允许范围将是在没有在另一个除法之前除以3的情况下进行评估的三倍。 请注意,细分操作会使舍入略微精确,但仍然足够接近以达到很多目的。

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

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

在进行任何整数除法之前,请检查以确定除数不为零。 另请注意,这假定为正商。 如果是负数,则舍入需要为-5,而不是+5。

转换的转换总是如此:

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

暂无
暂无

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

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