how to convert a fraction to float in ruby - ruby

I have a string "1/16" I want to convert it to float and multiply it by 45. However, I dont get the desired results.
I am trying in script/console
>> "1/16".to_f
=> 1.0
>> "1/16".to_f*45
=> 45.0
how can i get the desired result of 2.81
Bigger picture:
I have a drop down like this:
<%=select_tag :volume, options_for_select(["", "1 g", "1/16 oz", "1/8 oz","1/4 oz",
"1/2 oz", "1 oz", "1/8 lb", "1/4 lb", "Single", "Multi 5" ], "N/A") %>
whenever user selects oz value then i want to multiply it to 45
so i do:
first, *rest = params[:volume].to_s.split(/ /)
if rest.first=="oz"
#indprodprice = #prods.orig_price.to_i*first.to_f*28.3495
else
#indprodprice = #prods.orig_price.to_i*first.to_f*453.59237
end

Use Rational
>> (Rational(*("1/16".split('/').map( &:to_i )))*45).to_f
=> 2.8125

Looks like you're going to have to parse the fraction yourself. This will work on fractions and whole numbers, but not mixed numbers (ie: 1½ will not work.)
class String
def to_frac
numerator, denominator = split('/').map(&:to_f)
denominator ||= 1
numerator/denominator
end
end
"1/16".to_frac * 45

#Farrel was right, and since Ruby 1.9 includes Rational and String has a to_r-method things are easier:
puts ("1/16".to_r * 45).to_f #=> 2.8125
puts ("1/16".to_r * 45).to_f.round(2) #=> 2.81
In 2.0 it became even easier with a rational literal:
1/16r # => (1/16)

Related

Ruby: Convert dollar (String) to cents (Integer)

How do I convert a string with a dollar amount such as "5.32" or "100" to an integer amount in cents such as 532 or 10000?
I have a solution below:
dollar_amount_string = "5.32"
dollar_amount_bigdecimal = BigDecimal.new(dollar_amount_string)
cents_amount_bigdecimal = dollar_amount_bigdecimal * BigDecimal.new(100)
cents_amount_int = cents_amount_bigdecimal.to_i
but it seems wonky. I want to be sure because this will be an input to the PayPal API.
I've also tried the money gem, but it wasn't able to take strings as inputs.
You can use String#to_r ("to rational") to avoid round-off error.
def dollars_to_cents(dollars)
(100 * dollars.to_r).to_i
end
dollars_to_cents("12")
#=> 1200
dollars_to_cents("10.25")
#=> 1025
dollars_to_cents("-10.25")
#=> -1025
dollars_to_cents("-0")
#=> 0
d, c = dollar_amount_string.split(".")
d.to_i * 100 + c.to_i # => 532
I started with the original accepted answer, but had to make some important fixes along the way:
def dollars_to_cents(string=nil)
# remove all the signs and formatting
nums = string.to_s.strip.delete("$ CAD ,")
# add CENTS if they do not exit
nums = nums + ".00" unless nums.include?(".")
return (100 * nums.strip.to_r).to_i
end
So far works with these inputs:
CAD 1,215.92
CAD 1230.00
$11123.23
$123
43234.87
43,234.87

How to format a string with floats in Ruby using #{variable}?

I would like to format a string containing float variables including them with a fixed amount of decimals, and I would like to do it with this kind of formatting syntax:
amount = Math::PI
puts "Current amount: #{amount}"
and I would like to obtain Current amount: 3.14.
I know I can do it with
amount = Math::PI
puts "Current amount %.2f" % [amount]
but I am asking if it is possible to do it in the #{} way.
You can use "#{'%.2f' % var}":
irb(main):048:0> num = 3.1415
=> 3.1415
irb(main):049:0> "Pi is: #{'%.2f' % num}"
=> "Pi is: 3.14"
Use round:
"Current amount: #{amount.round(2)}"
You can do this, but I prefer the String#% version:
puts "Current amount: #{format("%.2f", amount)}"
As #Bjoernsen pointed out, round is the most straightforward approach and it also works with standard Ruby (1.9), not only Rails:
http://www.ruby-doc.org/core-1.9.3/Float.html#method-i-round
Yes, it's possible:
puts "Current amount: #{sprintf('%.2f', amount)}"

How do I round a float to a specified number of significant digits in Ruby?

It would be nice to have an equivalent of R's signif function in Ruby.
For example:
>> (11.11).signif(1)
10
>> (22.22).signif(2)
22
>> (3.333).signif(2)
3.3
>> (4.4).signif(3)
4.4 # It's usually 4.40 but that's OK. R does not print the trailing 0's
# because it returns the float data type. For Ruby we want the same.
>> (5.55).signif(2)
5.6
There is probably better way, but this seems to work fine:
class Float
def signif(signs)
Float("%.#{signs}g" % self)
end
end
(1.123).signif(2) # => 1.1
(11.23).signif(2) # => 11.0
(11.23).signif(1) # => 10.0
Here's an implementation that doesn't use strings or other libraries.
class Float
def signif(digits)
return 0 if self.zero?
self.round(-(Math.log10(self).ceil - digits))
end
end
I don't see anything like that in Float. Float is mostly a wrapper for the native double type and given the usual binary/decimal issues, I'm not that surprised that Float doesn't allow you to manipulate the significant digits.
However, BigDecimal in the standard library does understand significant digits but again, I don't see anything that allows you to directly alter the significant digits in a BigDecimal: you can ask for it but you can't change it. But, you can kludge around that by using a no-op version of the mult or add methods:
require 'bigdecimal'
a = BigDecimal.new('11.2384')
a.mult(1, 2) # the result is 0.11E2 (i.e. 11)
a.add(0, 4) # the result is 0.1124E2 (i.e. 11.24)
The second argument to these methods:
If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
Using BigDecimal will be slower but it might be your only choice if you need fine grained control or if you need to avoid the usual floating point problems.
Some of the previous answers and comments have alluded to this solution but this is what worked for me:
# takes in a float value and returns another float value rounded to
# given significant figures.
def round_to_sig_figs(val, sig_figs)
BigDecimal.new(val, sig_figs).to_f
end
You are probably looking for Ruby's Decimal.
You could then write:
require 'decimal/shortcut'
num = 1.23541764
D.context.precision = 2
num_with_2_significant_digits = +D(num.to_s) # => Decimal('1.2')
num_with_2_significant_digits.to_f # => 1.2000000000000002
Or if you prefer to use the same syntax add this as a function to class Float like this:
class Float
def signif num_digits
require 'decimal/shortcut'
D.context.precision = num_digits
(+D(self.to_s)).to_f
end
end
Usage would then be the same, i.e.
(1.23333).signif 3
# => 1.23
To use it, install the gem
gem install ruby-decimal
#Blou91's answer is nearly there, but it returns a string, instead of a float. This below works for me:
(sprintf "%.2f", 1.23456).to_f
So as a function,
def round(val, sig_figs)
(sprintf "%.#{sig_figs}f", val).to_f
end
Use sprintf if you want to print trailing zeros
2.0.0-p353 :001 > sprintf "%.3f", 500
=> "500.000"
2.0.0-p353 :002 > sprintf "%.4f", 500
=> "500.0000"
2.0.0-p353 :003 >

How do I preserve my float number in ruby

So I'm trying some code out to convert numbers into strings. However, I noticed that in certain cases it does not preserve the last two decimal places. For instance I type 1.01 and 1.04 for addition and I get back 2.04. If I type just 1.05 it preserves the number and returns it exactly. I get whats going on things are being rounded. I don't know how to prevent it from being rounded though. Should I just consider sending (1.01+1.04) to self as only one input?
Warning! I haven't tried this yet so don't know if its supported:
user_input = (1.04+1.01) #entry from user
user_input = gets.to_f
user_input.to_test_string
What I have so far:
class Float
def to_test_string
cents = self % 1
dollars = self - cents
cents = cents * 100
text = "#{dollars.to_i.en.numwords} dollars and #{cents.to_i.en.numwords} cents"
puts text
text
end
end
puts "Enter two great floating point numbers for adding"
puts "First number"
c = gets.to_f
puts "Second number"
d = gets.to_f
e = c+d
puts e.to_test_string
puts "Enter a great floating number! Example 10.34"
a = gets.to_f
puts a.to_test_string
Thanks for the help! Post some code up so I can try!
First of all: never use float for money — Use Float or Decimal for Accounting Application Dollar Amount?
irb> x = 1.01 + 1.04
=> 2.05
irb> y = x % 1
=> 0.04999999999999982
irb> (y * 100).to_i
=> 4
But if want it VERYVERYVERY much:
irb> (y * 100).round.to_i
=> 5
$ python
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 1.04+1.01
2.0499999999999998
Read this: What Every Computer Scientist Should Know About Floating-Point Arithmetic
Also, what Nakilon said.
This is not a problem with ruby, nor your code (although you need to get rid of .en.numwords); it is a problem with the binary floating point representation.
You should use a Fixnum or Bignum to represent the currency.
eg.
class Currency
def initialize str
unless str =~ /([0-9]+)\.([0-9]{2})/
raise 'invalid currency string'
end
#cents = $1.to_i * 100 + $2.to_i
end
end

Set the display precision of a float in Ruby

Is it possible to set the display precision of a float in Ruby?
Something like:
z = 1/3
z.to_s #=> 0.33333333333333
z.to_s(3) #=> 0.333
z.to_s(5) #=> 0.33333
Or do I have to override the to_s method of Float?
z.round(2) or x.round(3) is the simplest solution. See http://www.ruby-doc.org/core-1.9.3/Float.html#method-i-round.
That said, that will only ensure that it is no more than that many digits. In the case of 1/3 that is fine, but if you had say 0.25.round(3) you will get 0.25, not 0.250.
You can use sprintf:
sprintf("%0.02f", 123.4564564)
I would normally just do the conversion in open code, something like:
puts "%5.2f" % [1.0/3.0]
Ruby calls Kernel#format for expressions like this, because String has a core operator % defined on it. Think of it as printf for Ruby if that rings any bells for you.
Rubocop recommends using #format over #sprintf and using annotated string tokens.
The syntax for #format is
%[flags][width][.precision]type
Example:
# Ensure we store z as a float by making one of the numbers a float.
z = 1/3.0
# Format the float to a precision of three.
format('%<num>0.3f', num: z)
# => "0.333"
format('%<num>0.5f', num: z)
# => "0.33333"
# Add some text to the formatted string
format('I have $%<num>0.2f in my bank account.', num: z)
# => "I have $0.33 in my bank account."
References:
https://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Style/FormatString
https://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Style/FormatStringToken
You can use puts
z = #{'%.3f' % z}

Resources