Java:我如何执行整数除法,使其舍入到-无穷大而不是0?

Java:我如何执行整数除法,使其舍入到-无穷大而不是0?,java,math,integer,division,Java,Math,Integer,Division,(注意:与此不同,因为OP从未明确指定向0或-无穷大舍入) 表示整数除法向零舍入。如果我想要正数除数的类似于floor()的行为(我不关心负除数的行为),那么实现这一点的最简单方法是什么,它在数值上对所有输入都是正确的 int ifloor(int n, int d) { /* returns q such that n = d*q + r where 0 <= r < d * for all integer n, d where d > 0 *

注意:与此不同,因为OP从未明确指定向0或-无穷大舍入)

表示整数除法向零舍入。如果我想要正数除数的类似于
floor()
的行为(我不关心负除数的行为),那么实现这一点的最简单方法是什么,它在数值上对所有输入都是正确的

int ifloor(int n, int d)
{
    /* returns q such that n = d*q + r where 0 <= r < d
     * for all integer n, d where d > 0
     *
     * d = 0 should have the same behavior as `n/d`
     *
     * nice-to-have behaviors for d < 0:
     *   option (a). same as above: 
     *     returns q such that n = d*q + r where 0 <= r < -d
     *   option (b). rounds towards +infinity:
     *     returns q such that n = d*q + r where d < r <= 0
     */
}

long lfloor(long n, long d)
{
    /* same behavior as ifloor, except for long integers */
}
intiFloor(intn,intd)
{
/*返回q,使得n=d*q+r,其中0
*
*d=0应具有与'n/d'相同的行为`
*
*d<0的行为很好:
*选项(a)。同上:
*返回q,使得n=d*q+r,其中0(我在为
long
s做所有事情,因为
int
s的答案是相同的,只需将
int
替换为每个
long
,并将
Integer
替换为每个
long

你可以只是一个双除法的结果,否则

原始答复:

return n/d - ( ( n % d != 0 ) && ( (n<0) ^ (d<0) ) ? 1 : 0 );
(为完整起见,使用
BigDecimal
ROUND\u FLOOR
舍入模式也是一种选择。)

新编辑:现在,我只是想看看它可以优化到多大程度以获得乐趣。使用我迄今为止最好的方法是:

public static long lfloordiv2( long n, long d ){

    if( d >= 0 ){
        n = -n;
        d = -d;
    }
    long tweak = (n >>> (Long.SIZE-1) ) - 1;
    return (n + tweak) / d + tweak;
}

(使用比上述操作更便宜的操作,但字节码稍长(29比26))。

如果您可以使用第三方库,则有以下内容:和。(披露:我为Guava撰稿。)


如果您不想使用第三方库来实现这一点,您仍然可以查看实现。

n<0
d>0
时,有一个相当简洁的公式可以实现这一点:取n的位补,进行除法,然后取结果的位补

int ifloordiv(int n, int d)
{
    if (n >= 0)
        return n / d;
    else
        return ~(~n / d);
}
对于其余部分,一个类似的构造工作(与
ifloordiv
兼容,即通常的不变量
ifloordiv(n,d)*d+ifloord(n,d)==n
满足),给出的结果总是在
[0,d)
范围内

对于负除数,公式并不是很简洁。下面是
ifloordiv
ifloormod
的扩展版本,它们遵循了负除数的“很好拥有”行为选项(b)

int ifloordiv(int n, int d)
{
    if (d >= 0)
        return n >= 0 ? n / d : ~(~n / d);
    else
        return n <= 0 ? n / d : (n - 1) / d - 1;
}

int ifloormod(int n, int d)
{
    if (d >= 0)
        return n >= 0 ? n % d : d + ~(~n % d);
    else
        return n <= 0 ? n % d : d + 1 + (n - 1) % d;
}
intifloordiv(intn,intd)
{
如果(d>=0)
返回n>=0?n/d:~(~n/d);
其他的
返回n=0)
返回n>=0?n%d:d+~(~n%d);
其他的

return n这一定是重复的,但我找不到它,如果它不是重复的,那么我只是完全惊讶它在3年多的堆栈溢出后还没有出现。在剩余部分的
d<0
条件中,我想你有两个倒过来的符号。看起来你想要
0对:谢谢,我是说肯定的除数的版本。(它应该是向+无穷大舍入的)请不要把我引向Math.floor。如果它碰巧对
int
变量(我不确定)工作正常,它对
变量不起作用,因为精度不高。我马上就要出门了,但如果我能在周一抽查它的正确性,我将+1。谢谢+周末愉快…很好!一个琐碎的模糊优化:替换
(内德:小心:n*d可能会在溢出时产生不正确的结果。@JasonS这是一个XOR(
^
)不是
*
@trutheality:Gah,我是个白痴!谢谢;我会马上解决这个问题的!@trutheality:True,除了结果仍然是最小值,这在数学上是错误的(但正确的模2**,所以这可能足够好).我有一种不愉快的感觉,
d<0
还有其他的角落案例潜伏着,但我没有花时间弄清楚它们都是什么。也许我应该这么做。嗯,原来我不知道除法实际上会溢出。@trutheality:我编辑了最后一段;还有更好的吗?据我所知,那个案例真的是唯一的例子角落的箱子。为什么番石榴没有包含双打的除法功能?@voipp:你会怎么做?它和普通的双打除法有什么区别?
int ifloormod(int n, int d)
{
    if (n >= 0)
        return n % d;
    else
        return d + ~(~n % d);
}
int ifloordiv(int n, int d)
{
    if (d >= 0)
        return n >= 0 ? n / d : ~(~n / d);
    else
        return n <= 0 ? n / d : (n - 1) / d - 1;
}

int ifloormod(int n, int d)
{
    if (d >= 0)
        return n >= 0 ? n % d : d + ~(~n % d);
    else
        return n <= 0 ? n % d : d + 1 + (n - 1) % d;
}
return BigDecimal.valueOf(n).divide(BigDecimal.valueOf(d), RoundingMode.FLOOR).longValue();