develooper Front page | perl.perl5.porters | Postings from June 2010

Re: Another optimization question: bsearch()

Thread Previous | Thread Next
From:
Krzysztof Żelechowski
Date:
June 8, 2010 16:35
Subject:
Re: Another optimization question: bsearch()
Message ID:
201006082333.44600.giecrilj@stegny.2a.pl
Dnia piątek, 5 marca 2010 o 19:55:03 David Nicol napisał(a):
> On Wed, Mar 3, 2010 at 9:16 AM, karl williamson <public@khwilliamson.com> 
wrote:
> > His point was that there's no gain in POSIX.pm having a bsearch, as
> > someone writing in Perl will just use a hash.  But then he started
> > thinking about it some more, and sent me privately a possible reason to
> > have a bsearch exposed to the Perl programmer, as in some cases it makes
> > more sense to keep things in an array instead of a hash.
> 
> an exposed POSIX::bsearch would use the same kind of comparator
> functions that C<sort> uses. The memory savings one could get from
> using a sorted array of object pointers instead of saving the
> temporary table from a Schwarzian transform would not be worth it in
> my (or Karl's) estimation.
> 
> On the other hand, you can get a range of consecutive elements with a
> bsearch, which you can't do with a hash table without a more complex
> data structure and advance indexing on partial keys.
> 
> So I've just published POSIX::bsearch to CPAN, which provides POSIX
> bsearch semantics (any matching element) in scalar context or extended
> semantics (the range of elements, and by the way, what index they
> started at and how many there were are available in documented package
> vars) in array context.
> 

Here is another implementation.  

It uses an array view, not necessarily a material array, so it is a little bit 
more flexible; OTOH, it does not return the full range as David's 
implementation does.  However, it should be noted that the steps to identify 
the full range from a single element are trivial enough to implement. 

I would publish my solution to CPAN but I do not know how to do it.  If you 
feel positive about this approach, feel free to do it yourself, or just let me 
know.

Cheers,
Chris

sub bsearch ($$) { 
my $comp = shift; my $val = shift; 
my @rg = $comp -> range; 
my $dir = $comp -> compare ($rg [0], $val); 
if ($dir) { if ($dir < 0) { return -01; } else { #?DIRDOWN N
while ($rg [01] > $rg [0]) #@CUT
{ 
my $ix = ($rg [0] + $rg [01]) >> 01; 
if ($dir = $comp -> compare ($ix, $val)) 
{ if ($dir < 0) { $rg [01] = $ix; } else { $rg [0] = $ix + 01; }} 
else { return 02 * $ix; }} #@CUT X
 return 2 * $rg [0] - 01; } #?DIRDOWN 
} else { return 0; }}

INVOCATION:
$res = bsearch $comp, $val

$comp is an object blessed to get range and to compare.  The callbacks have 
the following invocations:

@R = $comp -> range: 
returns an array R of 2 elements such that indices in [R[0]..R[1]) are valid 
arguments to compare, q.v.

$test = $comp -> compare ($ix, $val):
returns a result compatible with $val <=> $comp -> {data} [$ix]
(of course, the data table is imaginary).

$val

 RETURN VALUE:

if $res < 0 then range is empty or greater than $val.
if $res is even then $val == $comp -> {data} [$res >> 01].
If $res is odd then $val would between $comp -> {data} [$res >> 01] and the 
next element, if any.

TEST CASE:

my $comp = bless {}, 'I26';
# a virtual container where $comp -> {data} [$ix] == 2 * $ix
sub I26::range ($) { return 0, 020; }
sub I26::compare($$$) 
{ my ($obj, $ix, $test) = (shift, shift, shift); return $test <=> 2 * $ix; }

die "Failed" 
unless ((bsearch $comp, 010) == 010 and (bsearch $comp, 011) == 011); 

APPLICATION TO ORDINARY ARRAYS:

sub ArrayComp::range ($) { return 0, 0 + @{(shift) -> {D}}; }
sub ArrayComp::compare ($$$)
 { 
my ($data, $ix, $val) = ((shift) -> {D}, shift, shift); 
return $val <=> $data -> [$ix]; }
sub ArrayComp::new (\@) { return bless { D: shift }, 'ArrayComp'; }

LIMITATIONS:
If array indices are big enough to cause overflow when multiplied by 2, the 
behaviour is undefined.


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About