Mysql big decimal


#1

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
from :0

How do I get the float value of ‘big decimal’ ?

Craig


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


#2

Craig W. 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,

Marnen Laibow-Koser
http://www.marnen.org
removed_email_address@domain.invalid

Craig


#3

On Wed, 2009-06-03 at 07:07 +0200, Marnen Laibow-Koser wrote:

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.


yeah, I’m sort of stuck in a rails 1.2.x time warp and am struggling
with a bunch of the changes in 2.3.x - thus, it wasn’t really the big
decimal thing of mysql that was the problem.

I forgot about to_f because frankly, I never used it. I primarily am
concerned with view code here so I had just stuck that code to extend
the Float class (which worked so well in 1.2.x)…

class Float
def to_fl(digits)
sprintf("%.#{digits}f",self)
end
end

and I could get a fixed number of digits whenever I wanted. Apparently
this is like a very ineffective way to go about things in 2.3.x and to_f
gives me whatever decimal places it believes are significant so I’m sort
of trying to figure out how to locate the magic genie again.

Craig


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


#4

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
a :decimal column).

–Matt J.


#5

2009/6/3 Craig W. removed_email_address@domain.invalid:

and I could get a fixed number of digits whenever I wanted. Apparently
this is like a very ineffective way to go about things in 2.3.x and to_f
gives me whatever decimal places it believes are significant so I’m sort
of trying to figure out how to locate the magic genie again.

Craig

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


#6

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

On Wed, 2009-06-03 at 06:59 -0700, Matt J. wrote:

class Float
Craig

This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


#7

Craig W. 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,

Marnen Laibow-Koser
http://www.marnen.org
removed_email_address@domain.invalid


#8

On Wed, 2009-06-03 at 19:36 +0200, Marnen Laibow-Koser wrote:

Craig W. 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.


well, the round(2) function will return 1.5 if that is the stored value
in big decimal which was unacceptable but I didn’t try
@price.round(2).to_f but I wonder which is faster/slower.

In reality, though, it tossed an error…

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.

Craig


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


#9

Craig W. 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,

Marnen Laibow-Koser
http://www.marnen.org
removed_email_address@domain.invalid


#10

On Wed, 2009-06-03 at 23:49 +0200, Marnen Laibow-Koser wrote:

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


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


#11

On Jun 3, 2009, at 7:12 PM, Craig W. wrote:

but I didn’t try
decimal,
=> #<Price stockid: “F34/CW/ES”, typeabbrev: “RE”, currabrev: “USD”,
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:

irb> require ‘bigdecimal’
=> true
irb> x = BigDecimal.new(“1.50”)
=> #BigDecimal:8569c,‘0.15E1’,8(8)
irb> x.to_s
=> “0.15E1”
irb> x.round(2)
=> #BigDecimal:802b4,‘0.15E1’,8(16)
irb> x.round(2).to_f
=> 1.5
irb> “%.2f”%[x.round(2)]
=> “1.50”
irb> x = BigDecimal.new(“1.5431”)
=> #BigDecimal:6b0d0,‘0.15431E1’,8(12)
irb> x.round(2)
=> #BigDecimal:6845c,‘0.154E1’,8(16)
irb> x.round(2).to_f
=> 1.54
irb> “%.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 B. http://agileconsultingllc.com
removed_email_address@domain.invalid