Forum: Ruby on Rails mysql big decimal

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Craig W. (Guest)
on 2009-06-03 02:43
(Received via mailing list)
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.
Marnen L. (Guest)
on 2009-06-03 09:07
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
Craig W. (Guest)
on 2009-06-03 09:54
(Received via mailing list)
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.
Colin L. (Guest)
on 2009-06-03 11:35
(Received via mailing list)
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
Matt J. (Guest)
on 2009-06-03 18:00
(Received via mailing list)
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.
Craig W. (Guest)
on 2009-06-03 20:02
(Received via mailing list)
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.
Marnen L. (Guest)
on 2009-06-03 21:36
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
Craig W. (Guest)
on 2009-06-04 00:39
(Received via mailing list)
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.
Marnen L. (Guest)
on 2009-06-04 01:49
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
Craig W. (Guest)
on 2009-06-04 03:14
(Received via mailing list)
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.
Rob B. (Guest)
on 2009-06-04 04:12
(Received via mailing list)
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
This topic is locked and can not be replied to.