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。
你可以试试这个:
\n\nif (((a < 0) ^ (b < 0)) && (a % b != 0))\n{\n return (a/b - 1);\n}\nelse\n{\n return (a/b);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n编辑(在下面的评论中进行一些讨论后):
\n\n如果不使用 if-else,我会这样:
\n\nreturn (a/b - Convert.ToInt32(((a < 0) ^ (b < 0)) && (a % b != 0)));\nRun Code Online (Sandbox Code Playgroud)\n\n注意:Convert.ToIn32(bool value)还需要跳转,参见方法实现:
return value? Boolean.True: Boolean.False;\nRun 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,808到9,223,372,036,854,775,807。)