The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Getting Half Way There

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
Getting Half Way There Posted: Apr 27, 2007 1:02 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Getting Half Way There
Feed Title: Travis Griggs - Blog
Feed URL: http://www.cincomsmalltalk.com/rssBlog/travis-rss.xml
Feed Description: This TAG Line is Extra
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Travis Griggs - Blog

Advertisement

In the previous post, I pointed out the usefulness of introducing the method mean: to actually represent those kinds of common calcuation. There is however, an even simpler abstraction, which is more interesting.

Dividing by two is the most common static divsion performed. Real world processes call for it all the time. So much we have a word for it: half. What if we explore adding the method for this mathematical expression to the system?

ArithmeticValue>>half
	^self / 2
Even on it's own this is handy. Ever centered a label?
	self bounds center - label extent / 2
There's a subtle bug in there that I have stumbled on more times than I care to recollect. The last two terms need to paren'ed. With a half method, I can more correctly express the intent
	self bounds center - label extent half
The code says what it's doing. The interesting thing about this method though, is that once we have it in place, we can exploit attributes of the receiver. Let us consider some baseline calculations:
Expression~ms for 10,000,000 reps
5 / 27300
6 / 2400
5.0 / 21950
5.0d / 22350
(11/2) / 28300
(8@10) / 25650
Now let's do the same with the half method
Expression~ms for 10,000,000 repsX faster
5 half45501.60
6 half9800.41
5.0 half15751.24
5.0d half19501.21
(11/2) half30502.72
(8@10) half28501.98
The astute observer will realize that though were sending a message, as opposed to sending messages that the VM optimizes away in glue code often, we're actually coming out faster in all but one case. The reason is that while the implementation in ArithmeticValue is a nice correct catch all implementation (it actually should probably be more correctly defined as self + self / self), every single subtype in the table can exploit something about itself to come out ahead of the naive / 2 computation. Let's look at them:

Integer

half
	"We can exploit some assumptions here and short circuit both."
	^self even 
		ifTrue: [self // 2]
		ifFalse: [Fraction basicNew setNumerator: self denominator: 2]
Basically Integers have two ways they can go. Half of an even integer is still an integer, so we can skip straight to integer division. And odd Integers are a special fraction that doesn't need to through all the GCD reduction that normal Fraction creation entails, so we can directly to the Fraction we want there. The even Integer is the one case where half is slower. But given an arbitrary sample of Integers, 50% of them should be odd, and if we look at the average times, we still come up with a net speed improvement of 1.40 for Integers in general.

Floats and Doubles

half
	"A multiply is always faster than a divide."
	^self * 0.5
Always faster to use a multiply than a divide. I have a hunch that on an x86 chip, this difference would be even more marked. Double has it's own that uses 0.5d.

Fraction

half
	"Sidestep reduction since halving a Fraction has no further reduction opportunity."
	^self species basicNew setNumerator: numerator denominator: denominator * 2
Here we take advantage of knowing we don't have to engage the whole fraction reduction engine.

Point

half
	^x half @ y half
Again, by knowning we'll make another point, we can skip the whole double dispatching engine that will engage to eventually divide each half by 2. And by reusing half here, we pick up the speed benefits of half for those reciever types where appropriate.

But what can this mean?

So coming full circle, with this in place, we can now write our original mean: method as
mean: anArithmeticValue
	^(self + anArithmeticValue) half
We've gained some speed, and some handy expressions that clarify many of these common computations.

Now I have to get back to finishing the Cairo presentation, the thing that started this little adventure.

Read: Getting Half Way There

Topic: Better UIUC VW Wiki Feed Previous Topic   Next Topic Topic: The End of Exclsuive Access

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use