地板整数除法

Eug*_*sky 7 .net c# math integer-arithmetic

在 C# 中是否有一种简单、高效和正确(即不涉及到/从 double 转换)的方法来进行地板整数除法(例如Python 提供)。

换句话说,以下的有效版本,不会遭受长/双转换损失。

(long)(Math.Floor((double) a / b))
Run Code Online (Sandbox Code Playgroud)

还是必须自己实现它,例如

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;
}
Run Code Online (Sandbox Code Playgroud)

*) 尽管 Division 运算符的 C# 4 规范将其保持打开状态,无论OverflowException是在内部引发unchecked,但实际上它确实抛出(在我的系统上)并且Visual Studio .NET 2003 版本甚至强制它抛出:

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

编辑

关于checked和 的unchecked被划掉的语句都很好,但checked实际上只是一个编译时概念,所以我的函数是否应该环绕或抛出无论如何取决于我,无论调用函数的代码是否在内部checked

Bha*_*kar 2

你可以试试这个:

\n\n
if (((a < 0) ^ (b < 0)) && (a % b != 0))\n{\n   return (a/b - 1);\n}\nelse\n{\n   return (a/b);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

编辑(在下面的评论中进行一些讨论后):

\n\n

如果不使用 if-else,我会这样:

\n\n
return (a/b - Convert.ToInt32(((a < 0) ^ (b < 0)) && (a % b != 0)));\n
Run Code Online (Sandbox Code Playgroud)\n\n

注意:Convert.ToIn32(bool value)还需要跳转,参见方法实现:

\n\n
return value? Boolean.True: Boolean.False;\n
Run Code Online (Sandbox Code Playgroud)\n\n

理论上,不可能计算a = long.MinValue和 的除法b = -1L,因为预期结果是a/b = abs(long.MinValue) = long.MaxValue + 1 > long.MaxValue。(long 的范围是\xe2\x80\x939,223,372,036,854,775,8089,223,372,036,854,775,807。)

\n

  • 谢谢L16H7。在实现上面的“FlooredIntDiv”时,我开始与您的解决方案类似,它与我的解决方案一样高效,而且我相信,和我的一样正确(我没有考虑您的解决方案是否捕获所有“0”极端情况),但是我选择了“if/else”路线,因为我认为它更容易阅读。所以它相当于我的示例实现,但既不更简单也不更高效。 (2认同)