如何在Java中进行整数除法并四舍五入并得到整数结果?

134
我刚刚写了一个小方法,用于计算手机短信的页数。我没有使用Math.ceil进行向上取整的选项,而且老实说它看起来非常丑陋。
这是我的代码:
public class Main {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
   String message = "today we stumbled upon a huge performance leak while optimizing a raycasting algorithm. Much to our surprise, the Math.floor() method took almost half of the calculation time: 3 floor operations took the same amount of time as one trilinear interpolation. Since we could not belive that the floor-method could produce such a enourmous overhead, we wrote a small test program that reproduce";

   System.out.printf("COunt is %d ",(int)messagePageCount(message));



}

public static double messagePageCount(String message){
    if(message.trim().isEmpty() || message.trim().length() == 0){
        return 0;
    } else{
        if(message.length() <= 160){
            return 1;
        } else {
            return Math.ceil((double)message.length()/153);
        }
    }
}

我不是很喜欢这段代码,正在寻找一种更优雅的方法来完成这个任务。希望得到的结果是3而不是3.0000000。有什么想法吗?


对于大多数商业代码而言,Math.ceil 更易读。 - xsilen T
9个回答

267

使用Math.ceil()并将结果强制转换为int型:

  • 这仍然比使用abs()避免双精度更快。
  • 在处理负数时,结果是正确的,因为-0.999将被向上舍入为0。

示例:

(int) Math.ceil((double)divident / divisor);

19
这应该是正确答案。 - Duane
1
@Duane,楼主说:“我没有使用Math.ceil向上取整的选项”。 - Hemmels
3
公道话,尽管我认为这是现在谷歌搜索结果中排名最高的“数学四舍五入”,但它有一个条件。很遗憾。 - Duane
1
为什么在这样一个简单的计算中需要进行强制类型转换?Java应该提供更智能的API。 - Alston
3
这应该是正确的答案吗?包括浮点数计算将不包括一些非直观的边缘情况和各种问题,只是为了舍入简单的整数除法?通常为了消除浮点问题,人们使用双精度,这只是使问题不那么突出,但并没有解决它们。https://introcs.cs.princeton.edu/java/91float/ - Anton Krug

143

要将整数除法向上舍入,可以使用以下方法:

import static java.lang.Math.abs;

public static long roundUp(long num, long divisor) {
    int sign = (num > 0 ? 1 : -1) * (divisor > 0 ? 1 : -1);
    return sign * (abs(num) + abs(divisor) - 1) / abs(divisor);
}

或者如果两个数字都是正数

public static long roundUp(long num, long divisor) {
    return (num + divisor - 1) / divisor;
}

2
我的意思是,尝试num=-2div=-3。 这将得到-6/-3=2,但0.666...应该四舍五入为1。 实际上,对于num <= 0 && div <= 0,它不起作用。 - user905686
2
我的编译器无法识别 abs() - 我不得不使用 Math.abs()... - Doug English
15
那是因为你忘了静态导入(static import)。 - Alex
3
在这个(第二个)函数中,您需要确保 num + divisor -1 <= Long.MAX_VALUE。还有一个稍微慢一些但没有这个限制的函数:(num / divisor) + (num % divisor == 0 ? 0 : 1)。 - Wouter
1
@toshi (n + d) / d 表示 n / d + 1,除非发生溢出。(n + (d - 1)) / d 在所有情况下都向上舍入,除非 n 是 d 的倍数。 - Peter Lawrey
显示剩余11条评论

61

另一个不太复杂的单行代码:

private int countNumberOfPages(int numberOfObjects, int pageSize) {
    return numberOfObjects / pageSize + (numberOfObjects % pageSize == 0 ? 0 : 1);
}

可以使用long代替int;只需更改参数类型和返回类型。


9
这应该是答案。它可能是最容易实现的方法,并且避免了执行任何额外不必要的步骤。当将数字类型转换为不同的类型时,它还可以避免小的加法问题。 - Chris Walter
好的解决方案。谢谢。 - ghui
最有效和最简单的解决方案。 - Raymond Chenon
这就是我所做的,但我没有费心将它们全部放在一行上。我来看看是否已经有了一种方法来改善对于不太擅长数学的新手的可读性,但我想我会坚持这样做。 - Kyle Zimmer

33

Google的Guava库在IntMath类中处理此问题:

IntMath.divide(numerator, divisor, RoundingMode.CEILING);
与这里的许多答案不同,它处理负数。当试图除以零时,它还会抛出适当的异常。

19
(message.length() + 152) / 153

这将返回一个“向上取整”的整数。


14
long numberOfPages = new BigDecimal(resultsSize).divide(new BigDecimal(pageSize), RoundingMode.UP).longValue();

1
使用内置函数+1 - Mehul Joisar

0

如果您想要计算a除以b向上取整,可以使用(a+(-a%b))/b


-1

在Peter的解决方案基础上,这是我发现对我有效的始终向正无穷大舍入的方法:

public static long divideAndRoundUp(long num, long divisor) {
    if (num == 0 || divisor == 0) { return 0; }

    int sign = (num > 0 ? 1 : -1) * (divisor > 0 ? 1 : -1);

    if (sign > 0) {
        return (num + divisor - 1) / divisor;
    }
    else {
        return (num / divisor);
    }
}

1
除零不是零,而应该是一个错误。 - Stephen Ostermiller

-2

这可能会有所帮助,, 将余数减去长度并使其成为可被整除的数字,然后将其除以153

int r=message.length()%153;       //Calculate the remainder by %153
return (message.length()-r)/153;  // find the pages by adding the remainder and 
                                  //then divide by 153 

如果 message.length() 小于 153 怎么办?你的想法很好,但我会做以下调整来解决这个问题: (message.length() + (153 - message.length() % 153)) / 153 - Rohit Banga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接