10

Say I have any of the following numbers:

230957 or 83487 or 4785

What is a way in Ruby I could return them as 300000 or 90000 or 5000, respectively?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
John
  • 3,430
  • 2
  • 31
  • 44

8 Answers8

7
def round_up(number)
  divisor = 10**Math.log10(number).floor
  i = number / divisor
  remainder = number % divisor
  if remainder == 0
    i * divisor
  else
    (i + 1) * divisor
  end
end

With your examples:

irb(main):022:0> round_up(4785)
=> 5000    
irb(main):023:0> round_up(83487)
=> 90000
irb(main):024:0> round_up(230957)
=> 300000
mikej
  • 65,295
  • 17
  • 152
  • 131
  • mikej, thanks for pointing out that my 'solution' wasn't rounding up. I deleted the entire solution to prevent confusion. – John Aug 03 '10 at 22:00
  • @John: I'd be interested in your solution, as I'm wanting something that'll round to the closest rather than round up. – Andrew Grimm Sep 16 '10 at 03:17
  • @Andrew if you change the condition in my method from `if remainder == 0` to `if remainder == 0 || remainder < divisor / 2` then it will round to the closest. If that isn't what you mean then if you post a separate question with some examples of what you want then I'll take a look. – mikej Sep 16 '10 at 09:03
6
def round_to_significant_digit(i, significant_digits = 1)
  exp = Math.log10(i).floor - (significant_digits - 1)
  (i / 10.0 ** exp).round * 10 ** exp
end

 >> [230957, 83487, 4785].collect{|i|round_to_significant_digit(i)}
 => [200000, 80000, 5000]

And for extra credit:

 >>  [230957, 83487, 4785].collect{|i|round_to_significant_digit(i, 2)}
 => [230000, 83000, 4800]
 >>  [230957, 83487, 4785].collect{|i|round_to_significant_digit(i, 3)}
 => [231000, 83500, 4790]
mrm
  • 5,001
  • 2
  • 32
  • 30
4

Math.round accepts negative numbers. If you are only looking for the nearest 10, you can do (my_num).round(-1).

The only drawback being that there's no way to incorporate ceil here, so it doesn't always round up -- 4.round(-1) will return 0.

c.apolzon
  • 406
  • 4
  • 6
2

In Rails, you may also like the "number_to_human" helper, which automatically chooses a good dimension to round to.

http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_to_human

Sprachprofi
  • 1,229
  • 12
  • 24
2

I haven't actually done any coding in Ruby, but you would be able to do that with a standard rounding function if you pushed it over to the digit you wanted first.

Example:

230957 / 100000(the resolution you want) = 2.30957

Round 2.30957 = 2, or Round to Ceiling/Round value + 0.5 to get it to go to the upper value rather than the lower.

2 or 3 * 100000(the resolution you want) = 200000 or 300000 respectively.

Hope this helps!

Jai Chauhan
  • 4,035
  • 3
  • 36
  • 62
Lunin
  • 370
  • 2
  • 9
1

Here is my version:

def round(num, nearest = nil, pivot = nil)
  negative = num < 0
  num = -num if negative
  precision = Math.log10(num).to_i rescue 1
  nearest ||= precision == 0 ? 10 : 10**precision
  pivot ||= nearest
  result = (num + pivot) / nearest * nearest
  negative ? -result : result
end

This method is very bloted and looks so ugly... BUT... it handles a few edge cases that the others dont such as:

  • 0
  • values under 10
  • negative numbers
  • The pivot point can be changed

Here are some examples of usage:

round(0)   # 0
round(1)   # 10
round(9)   # 10
round(10)  # 20
round(-10) # -20
round(100) # 1000

round(1, 1000)        # 1000
round(499, 1000, 500) # 0
round(500, 1000, 500) # 1000
br3nt
  • 9,017
  • 3
  • 42
  • 63
1

It looks a little ugly, but as a first shot (rounds up everytime) ...

>> (("230957".split("").first.to_i + 1).to_s + \
   ("0" * ("230957".size - 1))).to_i
=> 300000

Better (rounds correct):

>> (230957 / 10 ** Math.log10(230957).floor) * \
   10 ** Math.log10(230957).floor
=> 200000
miku
  • 181,842
  • 47
  • 306
  • 310
0

A simple suggestion:

def nearest_large_number value
  str = value.to_s.gsub(/^([0-9])/) { "#{$1}." }
  multiplicator = ("1" + "0" * str.split('.')[1].length).to_i
  str.to_f.ceil * multiplicator
end

To use it:

nearest_large_number 230957
=> 300000
Florent Morin
  • 842
  • 1
  • 10
  • 13