Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

when 1.6 != 1.6? -- newbie

0 views
Skip to first unread message

Mel Bohince

unread,
Apr 14, 2005, 5:55:39 PM4/14/05
to
Really enjoying Ruby so far, but now I'm confused. To help learn Ruby,
I've been translating the Java code in the "Head First Design Patterns"
book into Ruby, aware that many are built-in with Ruby. While mimicking
the Decorator pattern I'm getting a strange failure to an assert_equal.

The unit test excerpts:
@e = Expresso.new
@e.setSize('grande')
@e = Mocha.new(@e)
assert_equal(1.40, @e.cost(),"price check") --> pass
@e = Mocha.new(@e)
assert_equal("Expresso, Mocha, Mocha", @e.getDescription()) --> pass
#puts @e.cost() --> 1.6 ##sanity check, should be 1.00 + 0.20 + 0.20 +
0.20 = 1.6
#####
assert_equal(1.6, @e.cost(),"price check2") --> fail with:

1) Failure:
testConcreteCondiment(TestBeverages)
[/Users/mel/Documents/Ruby_files/patterns/decorator/test/
testbeverages.rb:70]:
price check2.
<1.6> expected but was
<1.6>.
5 tests, 21 assertions, 1 failures, 0 errors

Recreated in irb, the instance looks like:
=> #<Mocha:0x7a884 @beverage=#<Mocha:0x21c94
@beverage=#<Expresso:0x58310 @description="Expresso", @size=0.2>>>

Any clues to what I'm doing wrong? Is there a strategy to debug this
kind of thing? The debugger is not like I'm use too.

Thanks for any help you can offer.

Ruby 1.8.2 on OSX 10.3.8
-: -: -: -: -: -: -: -: \|/
-: -: -: -: -: -: -: -: cU
Mel Bohince
Project Manager,
Arkay Packaging Corporation
fe...@att.net

Florian Frank

unread,
Apr 14, 2005, 6:08:53 PM4/14/05
to
Mel Bohince wrote:

> Any clues to what I'm doing wrong?


When you're using assert_equal, you're comparing two floating point
numbers with ==. That's usually a bad idea, because rounding errors
can/will occur. Try using assert_in_delta(number1, number2, delta), to
find out, if |number1 - number2| <= delta instead.

Another tip: If you want to represent prices in your programs, don't use
floats at all. Use integers for the representation of the cent values
and all computations, and divide by 100 only for the string
representation of the numbers.

--
Florian Frank

Ilmari Heikkinen

unread,
Apr 14, 2005, 6:11:27 PM4/14/05
to

On 15.4.2005, at 00:55, Mel Bohince wrote:

> <1.6> expected but was
> <1.6>.

Floating point accuracy, the bane of mankind.
1.0 + 0.2 + 0.2 + 0.2 - 1.6
=> -2.22044604925031e-16

> Any clues to what I'm doing wrong? Is there a strategy to debug this
> kind of thing? The debugger is not like I'm use too.

Either do fixed-point decimals with integers and decimal point
divisor (100 => 1.00*100; 100 + 20 + 20 + 20 - 160 => 0)
or pick an error threshold and check that (a - b) < threshold
(1.0 + 0.2 + 0.2 + 0.2 - 1.6) < 0.01
=> true

Joe Van Dyk

unread,
Apr 14, 2005, 6:19:06 PM4/14/05
to
On 4/14/05, Mel Bohince <fe...@att.net> wrote:
> Really enjoying Ruby so far, but now I'm confused. To help learn Ruby,
> I've been translating the Java code in the "Head First Design Patterns"
> book into Ruby, aware that many are built-in with Ruby. While mimicking
> the Decorator pattern I'm getting a strange failure to an assert_equal.

I've found that a lot of those classical design patterns don't really
make much sense when using a duck-typed language.

Thoughts?

Neil Stevens

unread,
Apr 14, 2005, 6:23:25 PM4/14/05
to
On Fri, 15 Apr 2005 08:11:27 +0900, Ilmari Heikkinen wrote:
> Either do fixed-point decimals with integers and decimal point
> divisor (100 => 1.00*100; 100 + 20 + 20 + 20 - 160 => 0)
> or pick an error threshold and check that (a - b) < threshold
> (1.0 + 0.2 + 0.2 + 0.2 - 1.6) < 0.01
> => true

Just use BigDecimal. No need to get tricky.
--
Neil Stevens - ne...@hakubi.us

'A republic, if you can keep it.' -- Benjamin Franklin

Mark Hubbart

unread,
Apr 14, 2005, 6:33:12 PM4/14/05
to
On 4/14/05, Mel Bohince <fe...@att.net> wrote:

Here's a nice page that with a self-explanitory title:

"What Every Computer Scientist Should Know About Floating-Point Arithmetic"
<http://docs.sun.com/source/806-3568/ncg_goldberg.html>

The way money is usually handled is to either use integers for
pennies, or use a separate money class which stores money in that way.
A nice thing about doing this in Ruby is that once you create your
money class, you can add helper methods to Numeric:

class Numeric
def cents
Money.new(self.round)
end
def dollars
Money.new((self*100).round)
end
end

23.cents #==> $0.23
23.50.dollars #==> $23.50

cheers,
Mark

Aleksi

unread,
Apr 14, 2005, 8:18:53 PM4/14/05
to
Ilmari Heikkinen wrote:

Ilmari is right here. The way to check if the calculated value is close
enough to the expected value, please check:

http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit/Assertions.html#M000104

Usage being something like

required_accuracy = 0.0001
assert_equal(1.6, @e.cost(), required_accuracy,
"price check2") # --> does not fail anymore

- Aleksi

Douglas Livingstone

unread,
Apr 15, 2005, 6:31:47 AM4/15/05
to
On 4/15/05, Aleksi <foo...@fuzzball.org.net> wrote:
> http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit/Assertions.html#M000104
>
> Usage being something like

required_accuracy = 0.0001
assert_in_delta(1.6, @e.cost(), required_accuracy,

"price check2") # --> does not fail anymore

The link was good but it still had assert_equal in the code :)

Douglas

Mel Bohince

unread,
Apr 15, 2005, 11:19:41 AM4/15/05
to

> Try using assert_in_delta(number1, number2, delta), to
> find out, if |number1 - number2| <= delta instead.

Thanks to all for the help!

I'll remember the assert_in_delta in the future when testing on floats.

The point about avoiding float when doing currency is sound advice, yet
opens a new chapter of issues when deal with big numbers in special
pricing units of measure. Then Googled "Class Money" got a spiffy
"ruby" Money at <http://www2a.biglobe.ne.jp/~seki/ruby/sbpp8.html> and
a nice interface from junit.samples.money; ah, other have blazed and
paved the trail.

Thanks.


-: -: -: -: -: -: -: -: \|/
-: -: -: -: -: -: -: -: cU

mel

Mel Bohince

unread,
Apr 15, 2005, 12:14:49 PM4/15/05
to
Joe,

I'll defer to experienced, but yes, it seems like overkill when not a
strongly-typed lng.

I just wanted some hands-on experience as I read the Pick-Ax; thought
that working with some classic coding situations would be a good
contrived problem that would help me retain Ruby. (I spend most of my
work day writing in 4D which is not OO.) Also, the "Head First" book is
really motivating; the writing style is truly impressive.

-: -: -: -: -: -: -: -: \|/
-: -: -: -: -: -: -: -: cU

mel

0 new messages