地板整数除法

时间:2015-01-21 04:31:41

标签: c# .net math integer-arithmetic

在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规范OverflowExceptionuncheckedchecked内引发的,但实际上它确实抛出(在我的系统上)而Visual Studio .NET 2003 version甚至强制执行抛出:

  

如果左操作数是最小的可表示的int或long值而右操作数是-1,则在这种情况下总是抛出[..] System.OverflowException,无论操作是在已检查或未检查的上下文中发生的。

<击>

修改

关于uncheckedchecked的划线陈述都很好,但 checked实际上只是compile time concept ,所以无论我的函数是否应该回滚或抛出都取决于我,无论调用该函数的代码是否在{{1}}内。

3 个答案:

答案 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 = -1La/b = abs(long.MinValue) = long.MaxValue + 1 > long.MaxValue的除法。 (长的范围是–9,223,372,036,854,775,8089,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);