C# 地板整数除法

C# 地板整数除法,c#,.net,math,integer-arithmetic,C#,.net,Math,Integer Arithmetic,在C#中是否有一种简单、有效且正确的方法(即不涉及到双精度的转换)来进行地板整数除法(例如) 换言之,这是以下情况的有效版本,不会遭受长/双转换损失 (long)(Math.Floor((double) a / b)) 或者一个人必须自己实现它,比如 static long FlooredIntDiv(long a, long b) { if (a < 0) { if (b > 0) return (a - b + 1) /

在C#中是否有一种简单、有效且正确的方法(即不涉及到双精度的转换)来进行地板整数除法(例如)

换言之,这是以下情况的有效版本,不会遭受长/双转换损失

(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;
}
静态长FloorRedintDiv(长a、长b)
{
if(a<0)
{
如果(b>0)
返回(a-b+1)/b;
//如果(a==long.MinValue&&b==1)//请参见下面的*)
//抛出新的OverflowException();
}
如果(a>0),则为else
{
if(b<0)
报税表(a-b-1)/b;
}
返回a/b;
}
*)尽管除法运算符的C#4规范是否
OverflowException
在未选中的
中提出,但实际上它确实抛出(在我的系统上),甚至强制抛出:

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

编辑


关于
checked
unchecked
的划掉的语句都很好,但是
checked
实际上只是一个
,所以我的函数是应该换行还是抛出取决于我自己,无论调用函数的代码是否在
中被选中

它在任何健全的编程语言(遵循我们的正常操作顺序的编程语言)中的工作方式是
-1.0/3.0
相当于
-(1.0/3.0)
,即
-0.3333…
。所以如果你想把它转换成int,你需要考虑的其实是cast/floor操作符,而不是除法。因此,如果您想要此行为,则必须使用
(int)Math.Floor(a/b)
,或自定义代码。

您可以尝试以下操作:

if (((a < 0) ^ (b < 0)) && (a % b != 0))
{
   return (a/b - 1);
}
else
{
   return (a/b);
}

理论上,不可能计算
a=long.MinValue
b=-1L
的除法,因为预期结果是
a/b=abs(long.MinValue)=long.MaxValue+1>long.MaxValue
。(long的范围是
–9223372036854775808
9223372036854775807

您不需要自己实现这一点,
Math
类提供了一种用于进行欧氏除法的内置方法:

唯一的缺点是,您必须为剩余部分提供一个可分配的变量:

long remainder;
long quotient = Math.DivRem(a, b, out remainder);

你的意思是,除了将结果传递到
Math.Floor
,整数除法已经在这样做了,并没有直接调用
Math.Floor
,但结果是一样的,它会截断整个小数部分<代码>数学.楼层
在这种情况下是多余的。@maremp:仅适用于积极结果。请参阅OP的表格,了解与C#
/
运算符实现不同的“floor”负面结果示例。哦,是的@PeterDuniho,我忘记了这一点……这不是一个解决方案,但我相信您的代码在某些情况下可能会失败<代码>变量a=long.MinValue;var b=-1L
var a=long.MaxValue;var b=-1L.PS:^是xor运算符存储库L16H7。在实现上面的
FloorRedintDiv
时,我从类似于您的解决方案开始,它与我的解决方案一样高效,而且我相信,它与我的解决方案一样正确(我还没有考虑您的解决方案是否能捕获所有
0
角落案例),但我选择了
if/else
路线,因为我认为它更容易阅读。因此,它相当于我的示例实现,但既不简单也不高效。通常,“高效”公式不应使用任何“if”语句等。它应该完全基于低级算术运算符。如果我必须删除
If else
,我会这样做:
{return(a/b-Convert.ToInt32((a<0)^(b<0))&&(a%b!=0));}
。当bool转换为int时,我使用的是true=1和false=0这一事实。@L16H7仅供参考:您的解决方案为
a=long.MinValue
b=-1L
抛出一个
OverflowException
。我测试它是因为publicgk(错误地)建议我的解决方案可能会因为这些数字而失败。谢谢,我删除了我答案的这一部分。我在计算物理中学到的一些概念由于误用而被破坏,并以毫无意义的方式重新组合有一些规则/指导原则关于哪些操作部分应该强制转换,目标是由于浮点不精确而丢失最少的信息,但我从大学起就没有真正使用过这些规则/指导原则,因此忘记了具体细节。
Math.DivRem
的返回值与
a/b
相同,因此,不需要调用
Math.DivRem
。至于
a/b有什么问题
:如果a或b为负值,它不会给出最低的结果。
return value? Boolean.True: Boolean.False;
long remainder;
long quotient = Math.DivRem(a, b, out remainder);