Reno
Reno

Reputation: 2982

How to count the number of decimal places in a Float?

I am using Ruby 1.8.7 and Rails 2.3.5.

If I have a float like 12.525, how can a get the number of digits past the decimal place? In this case I expect to get a '3' back.

Upvotes: 12

Views: 12159

Answers (7)

Inx Maurya
Inx Maurya

Reputation: 1155

You can use this approach

def digits_after_decimal_point(n)
  splitted = n.to_s.split(".")
  if splitted.count > 1
    return 0 if splitted[1].to_f == 0
    return splitted[1].length
  else
   return 0
  end
end



# Examples
digits_after_decimal_point("1") #=> 0
digits_after_decimal_point("1.0") #=> 0
digits_after_decimal_point("1.01") #=> 2
digits_after_decimal_point("1.00000") #=> 0
digits_after_decimal_point("1.000001") #=> 6
digits_after_decimal_point(nil) #=> 0

Upvotes: 0

Alex Man
Alex Man

Reputation: 3

Olexandr's answer doesn't work for integer. Can try the following:

def decimals(num)
  if num
    arr = num.to_s.split('.')
    case arr.size
      when 1
        0
      when 2
        arr.last.size
      else
        nil
    end
  else
    nil
  end
end

Upvotes: 0

sarnold
sarnold

Reputation: 104080

You should be very careful with what you want. Floating point numbers are excellent for scientific purposes and mostly work for daily use, but they fall apart pretty badly when you want to know something like "how many digits past the decimal place" -- if only because they have about 16 digits total, not all of which will contain accurate data for your computation. (Or, some libraries might actually throw away accurate data towards the end of the number when formatting a number for output, on the grounds that "rounded numbers are more friendly". Which, while often true, means it can be a bit dangerous to rely upon formatted output.)

If you can replace the standard floating point numbers with the BigDecimal class to provide arbitrary-precision floating point numbers, then you can inspect the "raw" number:

> require 'bigdecimal'
=> true
> def digits_after_decimal_point(f)
>   sign, digits, base, exponent = f.split
>   return digits.length - exponent
> end
> l = %w{1.0, 1.1, 1000000000.1, 1.0000000001}
=> ["1.0,", "1.1,", "1000000000.1,", "1.0000000001"]
> list = l.map { |n| BigDecimal(n) }
=> [#<BigDecimal:7f7a56aa8f70,'0.1E1',9(18)>, #<BigDecimal:7f7a56aa8ef8,'0.11E1',18(18)>, #<BigDecimal:7f7a56aa8ea8,'0.1000000000 1E10',27(27)>, #<BigDecimal:7f7a56aa8e58,'0.1000000000 1E1',27(27)>]
> list.map { |i| digits_after_decimal_point(i) }
=> [0, 1, 1, 10]

Of course, if moving to BigDecimal makes your application too slow or is patently too powerful for what you need, this might overly complicate your code for no real benefit. You'll have to decide what is most important for your application.

Upvotes: 14

daniel
daniel

Reputation: 471

Can you subtract the floor and then just count how many characters left?

(12.525 -( 12.52­5.floor )).to­_s.length-­2 => 3

edit: nope this doesnt work for a bunch of reasons, negatives and 0.99999 issues

Upvotes: 0

Matt Greer
Matt Greer

Reputation: 62057

Here is a very simple approach. Keep track of how many times you have to multiple the number by 10 before it equals its equivalent integer:

def decimals(a)
    num = 0
    while(a != a.to_i)
        num += 1
        a *= 10
    end
    num   
end

decimals(1.234) # -> 3
decimals(10/3.0) # -> 16

Upvotes: 13

Oleksandr Skrypnyk
Oleksandr Skrypnyk

Reputation: 2830

Something like that, I guess:

n = 12.525
n.to_s.split('.').last.size

Upvotes: 27

Linuxios
Linuxios

Reputation: 35788

Like This:

theFloat.to_s.split(".")[1].length

It is not very pretty, but you can insert it as a method for Float:

class Float
    def decimalPlaces
      self.to_s.split(".")[1].length
    end
end

Upvotes: 3

Related Questions