in reply to Binary search algorithm.

The variant below has two features yours doesn't:

# Add $value to sorted @array, if it's not already there. my $idx = binsearch { $a <=> $b } $value, @array; splice(@array, ~$idx, 0, $value) if $idx < 0;
sub binsearch(&$\@) { my $compare = $_[0]; #my $value = $_[1]; my $array = $_[2]; my $i = 0; my $j = $#$array; return $j if $j == -1; my $ap = do { no strict 'refs'; \*{caller().'::a'} }; local *$ap; my $bp = do { no strict 'refs'; \*{caller().'::b'} }; local *$bp; *$ap = \($_[1]); for (;;) { my $k = int(($i+$j)/2); *$bp = \($array->[$k]); my $cmp = $compare->() or return $k; if ($cmp < 0) { $j = $k-1; return _unsigned_to_signed(~$k) if $i > $j; } else { $i = $k+1; return _unsigned_to_signed(~$i) if $i > $j; } } } sub _unsigned_to_signed { unpack('j', pack('J', $_[0])) }

I wonder if the following interface is better:

# Add $value to sorted @array, if it's not already there. my $idx = binsearch { $value <=> $::_ } @array; splice(@array, ~$idx, 0, $value) if $idx < 0;
sub binsearch(&\@) { my ($compare, $array) = @_; my $i = 0; my $j = $#$array; return $j if $j == -1; for (;;) { my $k = int(($i+$j)/2); my $cmp; $cmp = $compare->() for $array->[$k]; return $k if !$cmp; if ($cmp < 0) { $j = $k-1; return _unsigned_to_signed(~$k) if $i > $j; } else { $i = $k+1; return _unsigned_to_signed(~$i) if $i > $j; } } } sub _unsigned_to_signed { unpack('j', pack('J', $_[0])) }