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