在C#中是否有一种简单,有效和正确(即不涉及转换为双倍的转换)方式来执行 floored integer division (例如Python offers)。
换句话说,以下的有效版本,不会遭受长/双转换损失。
(long)(Math.Floor((double) a / b))
或者是否必须自己实施,例如。
static long FlooredIntDiv(long a, long b)
{
if (a < 0)
{
if (b > 0)
return (a - b + 1) / b;
// if (a == long.MinValue && b == -1) // see *) below
// throw new OverflowException();
}
else if (a > 0)
{
if (b < 0)
return (a - b - 1) / b;
}
return a / b;
}
<击>
*)尽管分区运算符leaves it open的C#4规范OverflowException
是unchecked
在checked
内引发的,但实际上它确实抛出(在我的系统上)而Visual Studio .NET 2003 version甚至强制执行抛出:
击>如果左操作数是最小的可表示的int或long值而右操作数是-1,则在这种情况下总是抛出[..] System.OverflowException,无论操作是在已检查或未检查的上下文中发生的。
<击> 撞击>
修改
关于unchecked
和checked
的划线陈述都很好,但 checked
实际上只是compile time concept ,所以无论我的函数是否应该回滚或抛出都取决于我,无论调用该函数的代码是否在{{1}}内。
答案 0 :(得分:1)
你可以试试这个:
if (((a < 0) ^ (b < 0)) && (a % b != 0))
{
return (a/b - 1);
}
else
{
return (a/b);
}
修改(经过以下评论中的一些讨论后):
不使用if-else,我会这样:
return (a/b - Convert.ToInt32(((a < 0) ^ (b < 0)) && (a % b != 0)));
注意:Convert.ToIn32(bool value)
也需要跳转,请参阅方法的implemention:
return value? Boolean.True: Boolean.False;
理论上,由于预期结果为a = long.MinValue
,因此无法计算b = -1L
和a/b = abs(long.MinValue) = long.MaxValue + 1 > long.MaxValue
的除法。 (长的范围是–9,223,372,036,854,775,808
到9,223,372,036,854,775,807
。)
答案 1 :(得分:0)
它在任何理智的编程语言(遵循我们的正常操作顺序)中的工作方式是-1.0/3.0
等同于-(1.0/3.0)
-0.3333...
。因此,如果你想将转换为int,那么你需要考虑的是施法/场地操作员,而不是分裂。因此,如果您需要此行为,则必须使用(int)Math.Floor(a/b)
或自定义代码。
答案 2 :(得分:0)
您不需要自己实现这一点,Math
类提供了执行欧几里得除法的内置方法:Math.DivRem()
唯一的缺点是您必须为其余部分提供一个可分配的变量:
long remainder;
long quotient = Math.DivRem(a, b, out remainder);