134

I just wrote a tiny method to count the number of pages for cell phone SMS. I didn't have the option to round up using Math.ceil, and honestly it seems to be very ugly.

Here is my code:

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);
        }
    }
}

I don't really like this piece of code and I'm looking for a more elegant way of doing this. With this, I'm expecting 3 and not 3.0000000. Any ideas?

Lernkurve
  • 20,203
  • 28
  • 86
  • 118
black sensei
  • 6,528
  • 22
  • 109
  • 188

9 Answers9

263

Use Math.ceil() and cast the result to int:

  • This is still faster than to avoid doubles by using abs().
  • The result is correct when working with negatives, because -0.999 will be rounded UP to 0

Example:

(int) Math.ceil((double)divident / divisor);
Joshua Kissoon
  • 3,269
  • 6
  • 32
  • 58
Roman
  • 3,094
  • 1
  • 14
  • 11
  • 19
    This should be the correct answer – Duane Dec 24 '16 at 03:16
  • 1
    @Duane The OP says "I didn't have the option to round up using Math.ceil" – Hemmels Nov 21 '17 at 17:14
  • 3
    Fair point, although I think this is the top "math rounding" hit on google now :) . Shame it has that condition on it. – Duane Nov 22 '17 at 18:10
  • 1
    Why do we need to do casting in such a simple calculation? Java should provide a smarter API. – Alston Jun 03 '19 at 09:55
  • 3
    This should be correct answer? Including floating point calculations will not include some of it's non-intuitive edge cases and various issues with it just to round up simple integer division? Often to negate the float issues people use double instead, that just makes the problems less prominent, but doesn't solve them https://introcs.cs.princeton.edu/java/91float/ – Anton Krug Dec 29 '20 at 15:58
141

To round up an integer division you can use

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);
}

or if both numbers are positive

public static long roundUp(long num, long divisor) {
    return (num + divisor - 1) / divisor;
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Note that this only works for `num >= 0`. – user905686 Jul 18 '12 at 09:48
  • It rounds to positive infinity. It doesn't round away from zero which is another option. – Peter Lawrey Jul 18 '12 at 09:55
  • 2
    I mean, try `num=-2` and `div=-3`. This ends up in `-6/-3=2` but `0,666..` should be rounded to `1`. In fact it doesn´t work for `num <= 0 && div <= 0`. – user905686 Jul 26 '12 at 11:16
  • @user905686 Good point, correcting. – Peter Lawrey Jul 26 '12 at 11:47
  • 2
    My compiler didn't recognize abs() - I had to use Math.abs()... – Doug English Mar 25 '13 at 08:35
  • 14
    @DougEnglish that's because you missed the static import. – Alex Jul 11 '13 at 13:51
  • Minor change for slightly better performance: int sign = (num > 0 != divisor > 0) ? -1 : 1); – Scott Feb 18 '15 at 20:21
  • 3
    In this (2nd) function you need num + divisor -1 <= Long.MAX_VALUE. There is a somewhat (is it slower?) function that doesn't have this liminitation: (num / divisor) + (num % divisor == 0 ? 0 : 1). – Wouter Jun 16 '16 at 21:11
  • Note that both approaches fail due to overflow when `num + divisor - 1 > Long.MAX_VALUE`. The `long` will overflow and the sign and value of the result will be wrong. I don't know of a great way around this problem (i.e., the obvious ones impose a branch or a bunch of bit manipulation). – BeeOnRope Jun 17 '16 at 21:56
  • @BeeOnRope It is worth knowing this could be a problem, though as you say there is no simple way to do this without adding significant complexity. – Peter Lawrey Jun 18 '16 at 15:49
  • 1
    @Peter Lawrey If you use the alternative I mentioned it doens't overflow. And your first function equals sign * 2nd function with abs values so nothing complex there. – Wouter Jun 18 '16 at 21:11
  • Could someone explain why it needs subtract 1 on the expression "(num + divisor - 1) / divisor" ?... – ohkts11 Jun 17 '18 at 05:26
  • 1
    @toshi `(n + d) / d` is `n / d + 1` unless there is an overflow. The `(n + (d - 1)) / d` rounds up in all cases except when n is a multiple of d. – Peter Lawrey Jun 22 '18 at 19:04
  • Great answer *except* for the names of the methods. What about `divideAndRoundUp`? This stuff is copied around everywhere, let's make it maintainable. – Maarten Bodewes Dec 20 '18 at 21:46
  • @MaartenBodewes I agree the name could be improved although divideXxxx sounds like the result will be a / b rather than something close to a. – Peter Lawrey Dec 24 '18 at 19:09
  • A good name for this is ceilDiv. Java already has has a Math.floorDiv, which one can use, or one can tweak it for an [efficient implementation](https://stackoverflow.com/a/30508570/2504891). – Vesal Feb 20 '20 at 00:03
60

Another one-liner that is not too complicated:

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

Could use long instead of int; just change the parameter types and return type.

popstr
  • 1,000
  • 9
  • 17
  • 9
    This should be the answer. It is probably the easiest method to implement and avoids doesn't perform any extra unnecessary steps. It also avoids minor addition problems when casting to different numeric types. – Chris Walter Apr 23 '14 at 23:58
  • Good solution. thanks – ghui Sep 25 '16 at 03:23
  • most effective and simplest solution. – Raymond Chenon Sep 08 '18 at 09:15
  • This was what I did but didn't bother to put it all on one line. Came looking to see if there was a method for it already to improve the readability for less mathy newbies, but I think I'll stick with it. – Kyle Zimmer Jul 14 '22 at 20:02
33

Google's Guava library handles this in the IntMath class:

IntMath.divide(numerator, divisor, RoundingMode.CEILING);

Unlike many answers here, it handles negative numbers. It also throws an appropriate exception when attempting to divide by zero.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
18
(message.length() + 152) / 153

This will give a "rounded up" integer.

dee-see
  • 23,668
  • 5
  • 58
  • 91
13
long numberOfPages = new BigDecimal(resultsSize).divide(new BigDecimal(pageSize), RoundingMode.UP).longValue();
mekazu
  • 2,545
  • 3
  • 23
  • 21
0

If you want to calculate a divided by b rounded up you can use (a+(-a%b))/b

-1

Expanding on Peter's solution, this is what I've found works for me to always round 'towards positive infinity':

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);
    }
}
Doug English
  • 286
  • 1
  • 10
-2

this might be helpfull,, Subtract the remainder to the legnth and make it a divisible number and then divide it with 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 
vivek_jonam
  • 3,237
  • 8
  • 32
  • 44
  • What if message.length() is < 153. Your idea is good but I would do to work around this: `(message.length() + (153 - message.length() % 153)) / 153` – Rohit Banga Jun 02 '18 at 07:32