[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

when 1.6 != 1.6? -- newbie

Mel Bohince

4/14/2005 9:56:00 PM

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
feet@att.net



9 Answers

Florian Frank

4/14/2005 10:09:00 PM

0

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

4/14/2005 10:11:00 PM

0


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

4/14/2005 10:19:00 PM

0

On 4/14/05, Mel Bohince <feet@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

4/14/2005 10:23:00 PM

0

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 - neil@hakubi.us

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

Mark Hubbart

4/14/2005 10:33:00 PM

0

On 4/14/05, Mel Bohince <feet@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.
>
> 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.

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_goldber...

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

4/15/2005 12:19:00 AM

0

Ilmari Heikkinen wrote:

> 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

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.ht...

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

4/15/2005 10:32:00 AM

0

On 4/15/05, Aleksi <foobar@fuzzball.org.net> wrote:
> http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit/Assertions.ht...
>
> 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

4/15/2005 3:20:00 PM

0


> 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/sbpp... and
a nice interface from junit.samples.money; ah, other have blazed and
paved the trail.

Thanks.
-: -: -: -: -: -: -: -: \|/
-: -: -: -: -: -: -: -: cU
mel




Mel Bohince

4/15/2005 4:15:00 PM

0

On Apr 14, 2005, at 6:19 PM, Joe Van Dyk wrote:
> On 4/14/05, Mel Bohince <feet@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?
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