Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can integer division be rounded up, instead of down?

Is there a way to round the result of integer division up to the nearest integer, rather than down?

For example, I would like to change the default behavior:

irb(main):001:0> 5 / 2
=> 2

To the following behavior:

irb(main):001:0> 5 / 2
=> 3
like image 940
ray Avatar asked Sep 19 '25 16:09

ray


1 Answers

This is rather an algorithm question than a ruby specific question.
Try (a + b - 1) / b. For example

(5 + 2 - 1) / 2  #=> 3
(10 + 3 - 1) / 3  #=> 4
(6 + 3 - 1) / 3  #=> 2

You can define an instance method, say divide_by, in the Integer class (monkey patch):

class Integer
  def divide_by(divisor)
    (self + divisor - 1) / divisor
  end
end

According to my benchmark result, it's about 1/2 times faster than the to_f then ceil solution.

CORRECTION

The method shown above gives wrong result when both the dividend and the divisor are negative.

Here's the method that gives the correct result in all cases: (a * 2 + b) / (b * 2)

a = 5
b = 2
(a * 2 + b) / (b * 2)  #=> 3

a = 6
b = 2
(a * 2 + b) / (b * 2)  #=> 3

a = 5
b = 1
(a * 2 + b) / (b * 2)  #=> 5

a = -5
b = 2
(a * 2 + b) / (b * 2)  #=> -2 (-2.5 rounded up to -2)

a = 5
b = -2
(a * 2 + b) / (b * 2)  #=> -2 (-2.5 rounded up to -2)

a = -5
b = -2
(a * 2 + b) / (b * 2)  #=> 3

a = 10
b = 0
(a * 2 + b) / (b * 2)  #=> raises ZeroDivisionError

The monkey patch should be

class Integer
  def divide_by(divisor)
    (self * 2 + divisor) / (divisor * 2)
  end
end

Mathematical Proof:

The dividend a and the divisor b meets the equation a = kb + m where a, b, k, m are all integers, b is not zero, and m is between b and 0 (can be 0).

For example, when a is 5 and b is 2, then a = 2b + 1, thus in this case, k = 2 and m = 1.

Another example for negative divisor, a is 5, b is -2, then a = -3b + (-1), thus k = -3 and m = -1.

(2a + b) / 2b
= (2(kb + m) + b) / 2b
= (2kb + b + 2m) / 2b

When m = 0

(2kb + b + 2m) / 2b
= (2k + 1)b / 2b
= k + (1 / 2)
= k + 0  # in Ruby
= k  # in Ruby

and since k = a / b, we got the correct answer.

When m is not 0,

(2kb + b + 2m) / 2b
= ((2k + 2)b - b + 2m) / 2b
= (k + 1) + (2m - b) / 2b

If b > 0, then 2m - b < b so (2m - b) / 2b < 1 / 2. So the second term is always 0 in integer division.

If b < 0, then 2m - b > b and still (2m - b) / 2b < 1 / 2 so the second term is still 0.

In either case, (2a + b) / 2b is rounded to k + 1 when m is not 0.

like image 50
Aetherus Avatar answered Sep 22 '25 06:09

Aetherus