Forum: RSpec Why can not a BigDecimal be compared to a Float via "==". How should I handle this???

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.
D5df9fcd7ef4c3c937435d7d6adeab2a?d=identicon&s=25 Greg Hauptmann (Guest)
on 2009-01-11 09:31
(Received via mailing list)
Hi,
Any suggestions on how to write an rspec expectation for equality when
you
get a BigDecimal back.  I see that "big_decimal_variable.should ==
123.23"
doesn't work as the ruby BigDecimal comparison (via ==) to the same
Float
value gives false (not true as you'd expect).  For background / as an
example see below:

        ?> bd
        => #<BigDecimal:221832c,'-0.32303E3',8(12)>
        >> f
        => -323.03
        >> f.class
        => Float
        >> bd.should == f
        Spec::Expectations::ExpectationNotMetError: expected: -323.03,
             got: #<BigDecimal:221832c,'-0.32303E3',8(12)> (using ==)
                from
/opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/expectations.rb:52:in
`fail_with'
                from
/opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/matchers/operator_matcher.rb:46:in
`fail_with_message'
                from
/opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/matchers/operator_matcher.rb:61:in
`__delegate_method_missing_to_given'
                from
/opt/local/lib/ruby/gems/1.8/gems/rspec-1.1.11/lib/spec/matchers/operator_matcher.rb:12:in
`=='
                from (irb):73
        >> bd == f
        => false
        >> f == bd
        => false

thanks
Greg
48641c4be1fbe167929fb16c9fd94990?d=identicon&s=25 Mark Wilden (Guest)
on 2009-01-11 10:42
(Received via mailing list)
On Sun, Jan 11, 2009 at 12:17 AM, Greg Hauptmann <
greg.hauptmann.ruby@gmail.com> wrote:

>
> Any suggestions on how to write an rspec expectation for equality when you
> get a BigDecimal back.  I see that "big_decimal_variable.should == 123.23"
> doesn't work as the ruby BigDecimal comparison (via ==) to the same Float
> value gives false (not true as you'd expect).
>

How about bd.to_s.should == 123.23.to_s ?

///ark
D5df9fcd7ef4c3c937435d7d6adeab2a?d=identicon&s=25 Greg Hauptmann (Guest)
on 2009-01-11 11:17
(Received via mailing list)
I've gone with the following     ai.amount.should ==
BigDecimal('-323.03')

However I'm still a bit surprised that Ruby itself does allow a good
"=="
test between a Float and a BigDecimal.  Perhaps there's a reason that
I'm
missing?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-01-11 15:42
(Received via mailing list)
On Sun, Jan 11, 2009 at 4:05 AM, Greg Hauptmann
<greg.hauptmann.ruby@gmail.com> wrote:
> I've gone with the following
>      ai.amount.should == BigDecimal('-323.03')
> However I'm still a bit surprised that Ruby itself does allow a good "=="
> test between a Float and a BigDecimal.  Perhaps there's a reason that I'm
> missing?

Very telling is this:

>> require 'bigdecimal'
=> true
>> BigDecimal.new(3333333.0) == 3333333.0
TypeError: can't convert Float into String
  from (irb):4:in `new'
  from (irb):4

As for why, I think you'll get some good insights if you post the
ruby-lang mailing list, but I can take shot.

BigDecimal has explicit precision. Float does not. Imagine the
developer at the bank explaining that the thousands of dollars
discrepancy last year was due to an average miscalculation of 0.00005
per transaction because sometimes the code used BigDecimal, and
sometimes it used Float.

Personally, I think this seeming annoyance is actually a good thing.

FWIW,
David
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2009-01-11 20:03
(Received via mailing list)
On Sun, Jan 11, 2009 at 9:21 AM, David Chelimsky
<dchelimsky@gmail.com>wrote:

> >> require 'bigdecimal'
> developer at the bank explaining that the thousands of dollars
> discrepancy last year was due to an average miscalculation of 0.00005
> per transaction because sometimes the code used BigDecimal, and
> sometimes it used Float.
>

Even more telling is this:
irb(main):001:0> 1.0 / 3.0
=> 0.333333333333333
irb(main):002:0> (1.0 / 3.00) ==  0.333333333333333
=> false

This has little to do with rspec or Ruby, and everything to do with
floats.

Floats are approximations, it's a mistake to thing of them as equivalent
to
the mathematical concept of real numbers, or even rational numbers.
There
are several issues here including

1. Floats are not infinite precision, they have a fixed number of bits
or
digits, this means that in-between any two consecutive real number which
CAN
be represented by a float, there are an infinite number of reals which
cannot.

2. As is the case in decimal fractions, where some rational numbers such
as
1/3 cannot be represented without an infinite number of decimal digits,
there are similar values dependent on the base used for the float
representation.

There's a whole branch of computer science, Numerical Analysis,
comprised in
large part of understanding how Floats differ from the mathematical
ideal.


--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
D5df9fcd7ef4c3c937435d7d6adeab2a?d=identicon&s=25 Greg Hauptmann (Guest)
on 2009-01-11 21:39
(Received via mailing list)
it would be nice in one's project if you could basically say "use
BigDecimal wherever you normally would have used a float", just to get
the
benefit but maintain ease of coding/readability etc - anyone know if
this is
possible?   Would it be enough to override Float's initializer and
return a
BigDecimal instead?
A91bd6cef23eb3516245a092e196c4da?d=identicon&s=25 Maurício Linhares (mauricio)
on 2009-01-11 22:20
(Received via mailing list)
This is a very bad idea, as you can break the whole runtime by doing
this, as many internal classes use floating point math. You would also
slow the world down, as operations using BigDecimals are some order of
magnitude slower than pure floating point math.

-
Maurício Linhares
http://alinhavado.wordpress.com/ (pt-br) | http://blog.codevader.com/
(en)



On Sun, Jan 11, 2009 at 6:33 PM, Greg Hauptmann
95a6493586dcb150d4fb4aec8f81b766?d=identicon&s=25 Tero Tilus (Guest)
on 2009-01-11 22:33
(Received via mailing list)
2009-01-11 18:17, Greg Hauptmann:
> Any suggestions on how to write an rspec expectation for equality when you
> get a BigDecimal back.  I see that "big_decimal_variable.should ==
> 123.23"

If you register keywords "comparison" and "float", you should train
yourself to cry out "delta" without even thinking.  ;)

Would this work for you?

  big_decimal_variable.should be_close(123.23, 0.005)
48641c4be1fbe167929fb16c9fd94990?d=identicon&s=25 Mark Wilden (Guest)
on 2009-01-11 23:27
(Received via mailing list)
On Sun, Jan 11, 2009 at 12:17 AM, Greg Hauptmann <
greg.hauptmann.ruby@gmail.com> wrote:


> Any suggestions on how to write an rspec expectation for equality when you
> get a BigDecimal back.  I see that "big_decimal_variable.should == 123.23"
> doesn't work as the ruby BigDecimal comparison (via ==) to the same Float
> value gives false (not true as you'd expect).
>

Noting there are two decimal places in your data, I might suggest using
the
Money plugin.

///ark
D5df9fcd7ef4c3c937435d7d6adeab2a?d=identicon&s=25 Greg Hauptmann (Guest)
on 2009-01-12 00:03
(Received via mailing list)
ok - thanks - seems like if one remembers to use "BigDecimal('10.1')",
then
instead of 10.1 in your code you should be ok then.

On Mon, Jan 12, 2009 at 6:45 AM, Maurício Linhares <
This topic is locked and can not be replied to.