mysql big decimal

I am using a legacy database with mysql.

I am working stuff through in the console and it tells me...

@price = Price.find(:first, :conditions => ["stockid = ? AND typeabbrev
= ?", @test, "WH"]).price
=> #<Price price: #<BigDecimal:b7a7341c,'0.115E1',8(12)>>

So I need to coerce this into a float...

I added to app/controllers/application_controller.rb (at the very bottom
of the file)...

# Provides extension to Numerics to provide subject decimal places
class Float
  def to_fl(digits)
    sprintf("%.#{digits}f",self)
  end
end

which used to work fine for me in Rails 1.2.6...but in the 2.3.2
console...

@price.to_i

=> 1

@price.to_fl(2)

NoMethodError: undefined method `to_fl' for
#<BigDecimal:b794c0fc,'0.115E1',8(12)>
        from (irb):30

How do I get the float value of 'big decimal' ?

Craig

Craig White wrote:
[...]

NoMethodError: undefined method `to_fl' for
#<BigDecimal:b794c0fc,'0.115E1',8(12)>
        from (irb):30
        from :0

How do I get the float value of 'big decimal' ?

Perhaps you should have checked the class documentation for BigDecimal
(part of the Ruby standard library). If I remember correctly,
BigDecimal#to_f will do what you want.

to_f is the standard name for such methods; to_fl is idiosyncratic, and
will cause problems if the consumers of your API expect to_f.

Best,

Craig White wrote:
[...]
> NoMethodError: undefined method `to_fl' for
> #<BigDecimal:b794c0fc,'0.115E1',8(12)>
> from (irb):30
> from :0
>
> How do I get the float value of 'big decimal' ?
>

Perhaps you should have checked the class documentation for BigDecimal
(part of the Ruby standard library). If I remember correctly,
BigDecimal#to_f will do what you want.

to_f is the standard name for such methods; to_fl is idiosyncratic, and
will cause problems if the consumers of your API expect to_f.

I am not sure whether you still have a problem. It is not strictly
correct to say that to_f gives me whatever decimal places it believes
are significant. A float will always contain as many digits as it can
hold. Is the problem that you wish to display it to a certain number
of digits? If so then you can use sprintf.

Alternatively of course there is the question of whether you need to
convert it to a float in the first place. Can you just keep it as
BigDecimal?

Colin

The problem is that you're defining this method (to_fl) on Float,
while AR is returning you a BigDecimal. Have you tried defining the
method in the correct class?

You don't appear to really want the "float value"; for large numbers,
it will lose a lot of precision (and thus the advantage of storing in

--Matt Jones

Thanks - I see said the blind man...

all I had to do was to first convert big decimal to float and then the
sprint function worked.

@price.to_f.to_fl(2) and I get what I wanted in the view...something
displayed to 2 decimal places. The value is already stored with
big_decimal precision...I just didn't know how to format it in a view,
which turned out to be trickier than if I just a float value.

Craig

Craig White wrote:

Thanks - I see said the blind man...

all I had to do was to first convert big decimal to float and then the
sprint function worked.

@price.to_f.to_fl(2) and I get what I wanted in the view...

Your Float#to_fl method is unnecessary and has semantics that will
confuse experienced Ruby programmers. Try @price.round(2).to_f.

Best,

Craig White wrote:
> Thanks - I see said the blind man...
>
> all I had to do was to first convert big decimal to float and then the
> sprint function worked.
>
> @price.to_f.to_fl(2) and I get what I wanted in the view...

Your Float#to_fl method is unnecessary and has semantics that will
confuse experienced Ruby programmers. Try @price.round(2).to_f.

Craig White wrote:
[...]

----
well, the round(2) function will return 1.5 if that is the stored value
in big decimal which was unacceptable

Huh? I don't understand what you're saying.

but I didn't try
@price.round(2).to_f but I wonder which is faster/slower.

In reality, though, it tossed an error...

Again, I don't understand. Did you try it or not?

undefined method `round' for #<Price:0xb6e1bf20>

which I think is back to my original problem of having a big decimal,
that must be converted to a float before it can be rounded.

No. BigDecimal#round should work as I just explained -- at least it
does on my system. Are you sure @price is actually holding a
BigDecimal?

Craig

Best,

Craig White wrote:
[...]
> ----
> well, the round(2) function will return 1.5 if that is the stored value
> in big decimal which was unacceptable

Huh? I don't understand what you're saying.

> but I didn't try
> @price.round(2).to_f but I wonder which is faster/slower.
>
> In reality, though, it tossed an error...

Again, I don't understand. Did you try it or not?

>
> undefined method `round' for #<Price:0xb6e1bf20>
>
> which I think is back to my original problem of having a big decimal,
> that must be converted to a float before it can be rounded.

No. BigDecimal#round should work as I just explained -- at least it
does on my system. Are you sure @price is actually holding a
BigDecimal?

Craig White wrote:
[...]

----
well, the round(2) function will return 1.5 if that is the stored value
in big decimal which was unacceptable

Huh? I don't understand what you're saying.

but I didn't try
@price.round(2).to_f but I wonder which is faster/slower.

In reality, though, it tossed an error...

Again, I don't understand. Did you try it or not?

undefined method `round' for #<Price:0xb6e1bf20>

which I think is back to my original problem of having a big decimal,
that must be converted to a float before it can be rounded.

No. BigDecimal#round should work as I just explained -- at least it
does on my system. Are you sure @price is actually holding a
BigDecimal?

----
console session...

_>> @price = Price.find(:first, :conditions => ["stockid = ?",
"F34/CW/ES"])
=> #<Price stockid: "F34/CW/ES", typeabbrev: "RE", currabrev: "USD",
debtorno: " ", price: #<BigDecimal:b7dc83ec,'0.15E1',8(12)>, branchcode:
" ">
_>> @price.price
=> #<BigDecimal:b7dacaac,'0.15E1',8(12)>
_>> @price.price.round(2)
=> #<BigDecimal:b7d9a4b0,'0.15E1',8(16)>
_>> @price.price.round(2).to_f
=> 1.5
_>> @price.price.round(2).to_fl(2)
NoMethodError: undefined method `to_fl' for
#<BigDecimal:b7ee9f64,'0.15E1',8(16)>
       from (irb):8
_>> @price.price.round(2).to_f.to_fl(2)
=> "1.50"
_>> @price.price.to_f.to_fl(2)
=> "1.50"
_>> @price.price.to_f.round(2)
=> 1.5

Craig

I think you two are talking past each other a bit.

Marnen is describing BigDecimal correctly:

require 'bigdecimal'

=> true

x = BigDecimal.new("1.50")

=> #<BigDecimal:8569c,'0.15E1',8(8)>

x.to_s

=> "0.15E1"

x.round(2)

=> #<BigDecimal:802b4,'0.15E1',8(16)>

x.round(2).to_f

=> 1.5

"%.2f"%[x.round(2)]

=> "1.50"

x = BigDecimal.new("1.5431")

=> #<BigDecimal:6b0d0,'0.15431E1',8(12)>

x.round(2)

=> #<BigDecimal:6845c,'0.154E1',8(16)>

x.round(2).to_f

=> 1.54

"%.2f"%[x.round(2)]

=> "1.54"

However, Craig, you seem to want a formatted output for your Price model where the #price attribute happens to be a BigDecimal.

class Price
   def formatted
     "%.2f"%[self.price.round(2)]
   end
end

Then you should have:
  @price = Price.find(:first, :conditions => ["stockid = ?","F34/CW/ES"])
  @price.formatted
  => "1.50"

You might also want to roll your own helper similar to number_to_currency

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com