Java:如何执行整数除法,使其四舍五入为 -Infinity 而不是 0?

2022-09-04 08:35:31

(注意与此另一个问题不同,因为OP从未明确指定舍入为0或-无穷大)

JLS 15.17.2 表示整数除法四舍五入为零。如果我想要正除数的类似行为(我不关心负除数的行为),那么实现对所有输入的数值正确的最简单的方法是什么?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 */
}

(更新:我想有一个解决方案和算术。intlong


答案 1

如果你可以使用第三方库,Guava有这个:IntMath.divide(int,int,RoundingMode.FLOOR)LongMath.divide(int,int,RoundingMode.FLOOR)(披露:我为番石榴做出贡献。

如果您不想为此使用第三方库,您仍然可以查看实现。


答案 2

(我正在为s做任何事情,因为s的答案是相同的,只需替换每个和每个。longintintlongIntegerLong

你可以只是Math.floor一个双除的结果,否则...

原答:

return n/d - ( ( n % d != 0 ) && ( (n<0) ^ (d<0) ) ? 1 : 0 );

优化答案:

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

    long q = n/d;
    if( q*d == n ) return q;
    return q - ((n^d) >>> (Long.SIZE-1));
}

(为完整起见,使用 带舍入模式的 也是一个选项。BigDecimalROUND_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))。