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

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

当前回答

最后一个基于int的答案

对于有符号整数:

int div = a / b;
if (((a ^ b) >= 0) && (a % b != 0))
    div++;

对于无符号整数:

int div = a / b;
if (a % b != 0)
    div++;

这个答案的原因

整数除法'/'的定义是四舍五入为零(规范的7.7.2),但我们想四舍五入。这意味着否定的答案已经被正确舍入,但肯定的答案需要调整。

非零的正答案很容易被发现,但是零答案有点棘手,因为它既可以是负数的四舍五入,也可以是正数的四舍五入。

最安全的方法是通过检查两个整数的符号是否相同来检测答案什么时候应该是正数。在这种情况下,两个值上的整数异或运算符'^'将导致0符号位,这意味着结果是非负的,因此检查(a ^ b) >= 0确定在舍入之前结果应该是正的。还要注意,对于无符号整数,每个答案显然都是正的,所以可以省略这个检查。

剩下的唯一检查是是否发生了舍入,其中a % b != 0将完成该工作。

经验教训

算术(整数或其他)并不像看起来那么简单。任何时候都需要仔细思考。

此外,虽然我的最终答案可能不像浮点数的答案那样“简单”或“明显”,甚至可能“快速”,但它对我来说有一个非常强大的救赎品质;我现在已经通过推理得出了答案,所以我实际上确定它是正确的(直到有更聪明的人告诉我,他偷偷地瞥了埃里克一眼)。

为了对浮点答案有同样的确定性感觉,我必须做更多(可能更复杂)的思考,是否有任何条件下浮点精度可能会妨碍,以及Math。“天花板”也许在“刚刚好”的输入上做了一些不受欢迎的事情。

走过的路

Replace(注意,我用myInt2替换了第二个myInt1,假设这就是你的意思):

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

:

(myInt1 - 1 + myInt2) / myInt2

唯一需要注意的是,如果myInt1 - 1 + myInt2溢出了您正在使用的整数类型,则可能得不到您所期望的结果。

错误的原因:-1000000和3999应该是-250,而这个是-249

编辑: 考虑到这与其他负myInt1值的整数解决方案具有相同的错误,可能更容易执行如下操作:

int rem;
int div = Math.DivRem(myInt1, myInt2, out rem);
if (rem > 0)
  div++;

这应该在div中只使用整数操作给出正确的结果。

错误的原因:-1和-5应该是1,而这个是0

编辑(再一次,充满感情地): 除法算符舍入到零;对于负结果,这是完全正确的,所以只有非负结果需要调整。同时考虑到DivRem无论如何只执行一个/和一个%,让我们跳过调用(并从简单的比较开始,以避免在不需要时进行模计算):

int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
    div++;

错误的原因:-1和5应该是0,而这个是1

(在我为上次尝试辩护的时候,当我的大脑告诉我我已经晚睡了2个小时的时候,我就不应该尝试一个理性的答案)

其他回答

这里所有解决方案的问题要么是它们需要强制转换,要么是它们有一个数值问题。转换为float或double总是一种选择,但我们可以做得更好。

当您使用来自@jerryjvl的答案代码时

int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
    div++;

有一个舍入误差。1 / 5会四舍五入,因为1% 5 != 0。但这是错误的,因为只有当用3替换1时才会发生舍入,所以结果是0.6。当计算给我们的值大于或等于0.5时,我们需要找到一种方法来四舍五入。上面例子中的模运算符的结果范围从0到myInt2-1。只有当余数大于除数的50%时,才会进行舍入运算。调整后的代码是这样的:

int div = myInt1 / myInt2;
if (myInt1 % myInt2 >= myInt2 / 2)
    div++;

当然,我们在myInt2 / 2也有一个舍入问题,但是这个结果将为您提供一个比这个站点上其他结果更好的舍入解决方案。

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

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

四舍五入,我想你的意思是总是从零开始。如果没有任何类型转换,请使用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;
}

您可以编写一个helper。

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

上面的一些答案使用浮动,这是低效的,真的没有必要。对于无符号整数,这是int1/int2的有效答案:

(int1 == 0) ? 0 : (int1 - 1) / int2 + 1;

对于有符号int型,这是不正确的