我想确保整数的除法在必要时总是四舍五入。还有比这更好的办法吗?有很多演员都在选角。: -)

(int)Math.Ceiling((double)myInt1 / myInt2)

当前回答

四舍五入,我想你的意思是总是从零开始。如果没有任何类型转换,请使用Math.DivRem()函数

/// <summary>
/// Divide a/b but always round up
/// </summary>
/// <param name="a">The numerator.</param>
/// <param name="b">The denominator.</param>
int DivRndUp(int a, int b)
{
    // remove sign
    int s = Math.Sign(a) * Math.Sign(b);
    a = Math.Abs(a);
    b = Math.Abs(b);
    var c = Math.DivRem(a, b, out int r);
    // if remainder >0 round up
    if (r > 0)
    {
        c++;
    }
    return s * c;
}

如果roundup的意思是不管符号是什么,总是向上,那么

/// <summary>
/// Divide a/b but always round up
/// </summary>
/// <param name="a">The numerator.</param>
/// <param name="b">The denominator.</param>
int DivRndUp(int a, int b)
{
    // remove sign
    int s = Math.Sign(a) * Math.Sign(b);
    a = Math.Abs(a);
    b = Math.Abs(b);
    var c = Math.DivRem(a, b, out int r);
    // if remainder >0 round up
    if (r > 0)
    {
        c+=s;
    }
    return s * c;
}

其他回答

你可以使用下面这样的东西。

a / b + ((Math.Sign(a) * Math.Sign(b) > 0) && (a % b != 0)) ? 1 : 0)

更新:这个问题是我2013年1月博客的主题。谢谢你的好问题!


获得正确的整数算术是困难的。正如迄今为止已经充分证明的那样,当你试图做一个“聪明”的把戏时,很可能你犯了一个错误。当发现缺陷时,修改代码来修复缺陷而不考虑修复是否会破坏其他东西,这不是一种很好的解决问题的技术。到目前为止,我想我们已经给出了5个不同的错误整数算术解来解决这个完全不是特别难的问题。

处理整数算术问题的正确方法——也就是说,增加第一次得到正确答案的可能性的方法——是仔细地处理问题,一步一步地解决它,并在此过程中使用良好的工程原理。

首先阅读您要替换的产品的规格说明。整数除法规范明确规定:

The division rounds the result towards zero The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs If the left operand is the smallest representable int and the right operand is –1, an overflow occurs. [...] it is implementation-defined as to whether [an ArithmeticException] is thrown or the overflow goes unreported with the resulting value being that of the left operand. If the value of the right operand is zero, a System.DivideByZeroException is thrown.

我们想要的是一个整除法函数,它计算商,但结果总是向上舍入,而不是总是趋于零。

所以为这个函数写一份说明。我们的函数int DivRoundUp(int除,int除数)必须为每个可能的输入定义行为。这种未定义的行为非常令人担忧,所以让我们消除它。我们会说我们的操作有这样的规范:

如果除数为零,操作抛出 如果被除数为int,则抛出操作。Minval和除数是-1 如果没有余数——除法为“偶数”——则返回值为整商 否则,它返回大于商的最小整数,也就是说,它总是四舍五入。

现在我们有了一个规范,所以我们知道我们可以提出一个可测试的设计。假设我们添加了一个额外的设计准则,即问题只能用整数算术来解决,而不是将商计算为双精度,因为“双精度”解决方案在问题声明中已被明确拒绝。

那么我们需要计算什么呢?显然,为了满足我们的规范,同时只使用整数运算,我们需要知道三个事实。首先,整数商是多少?第二,除法没有余数吗?第三,如果不是,整数商是向上舍入还是向下舍入?

现在我们有了规范和设计,就可以开始编写代码了。

public static int DivRoundUp(int dividend, int divisor)
{
  if (divisor == 0 ) throw ...
  if (divisor == -1 && dividend == Int32.MinValue) throw ...
  int roundedTowardsZeroQuotient = dividend / divisor;
  bool dividedEvenly = (dividend % divisor) == 0;
  if (dividedEvenly) 
    return roundedTowardsZeroQuotient;

  // At this point we know that divisor was not zero 
  // (because we would have thrown) and we know that 
  // dividend was not zero (because there would have been no remainder)
  // Therefore both are non-zero.  Either they are of the same sign, 
  // or opposite signs. If they're of opposite sign then we rounded 
  // UP towards zero so we're done. If they're of the same sign then 
  // we rounded DOWN towards zero, so we need to add one.

  bool wasRoundedDown = ((divisor > 0) == (dividend > 0));
  if (wasRoundedDown) 
    return roundedTowardsZeroQuotient + 1;
  else
    return roundedTowardsZeroQuotient;
}

这聪明吗?不。漂亮吗?不。短吗?不。根据说明书正确吗?我相信是这样的,但我还没有完全测试过。不过看起来还不错。

我们是专业人士;使用良好的工程实践。研究您的工具,指定所需的行为,首先考虑错误情况,并编写代码以强调其明显的正确性。当你发现一个错误时,在你随机地开始交换比较方向和破坏已经有效的东西之前,考虑一下你的算法是否有严重的缺陷。

使用扩展方法的绝佳机会:

public static class Int32Methods
{
    public static int DivideByAndRoundUp(this int number, int divideBy)
    {                        
        return (int)Math.Ceiling((float)number / (float)divideBy);
    }
}

这使得你的代码超级可读:

int result = myInt.DivideByAndRoundUp(4);

到目前为止,这里所有的答案似乎都过于复杂。

在c#和Java中,对于正的被除数和除数,你只需要做:

( dividend + divisor - 1 ) / divisor 

资料来源:《数字转换》,罗兰·巴恪思,2001年

您可以编写一个helper。

static int DivideRoundUp(int p1, int p2) {
  return (int)Math.Ceiling((double)p1 / p2);
}