我想确保整数的除法在必要时总是四舍五入。还有比这更好的办法吗?有很多演员都在选角。: -)
(int)Math.Ceiling((double)myInt1 / myInt2)
我想确保整数的除法在必要时总是四舍五入。还有比这更好的办法吗?有很多演员都在选角。: -)
(int)Math.Ceiling((double)myInt1 / myInt2)
当前回答
使用扩展方法的绝佳机会:
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);
其他回答
最后一个基于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个小时的时候,我就不应该尝试一个理性的答案)
上面的一些答案使用浮动,这是低效的,真的没有必要。对于无符号整数,这是int1/int2的有效答案:
(int1 == 0) ? 0 : (int1 - 1) / int2 + 1;
对于有符号int型,这是不正确的
对于有符号整数或无符号整数。
Q = x / y + !(((x < 0) != (y < 0)) || !(x % y));
有符号的股利和无符号的因子。
Q = x / y + !((x < 0) || !(x % y));
对于无符号股利和有符号因子。
Q = x / y + !((y < 0) || !(x % y));
对于无符号整数。
Q = x / y + !!(x % y);
零除数失败(与本机操作一样)。
不能溢出。
优雅而正确。
理解这种行为的关键是认识到截断、下限和上限划分的区别。c# / c++是被截断的。当商为负(即运算符符号不同)时,截断是一个上限(更少的负)。否则截断是一个底(不太正)。
因此,如果有余数,如果结果为正,则加1。模也是一样的,只是加了除数。地板是一样的,但是在相反的条件下减去。
使用扩展方法的绝佳机会:
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年