Acme-Tools

 view release on metacpan or  search on metacpan

t/09_rank_pushsort_binsearch.t  view on Meta::CPAN

#perl Makefile.PL;make;ATDEBUG=1 perl -Iblib/lib t/09_rank_pushsort_binsearch.t
use lib '.'; BEGIN{require 't/common.pl'}
use Test::More tests => 62;

my @a=(1,10,20,50,70,90,120,130);
testsearch(1,@a);

@a=(1..20);    testsearch(1,@a);
@a=(1..1000);  testsearch(0,@a);
@a=(1..2000);  testsearch(0,@a);
@a=(1..4000);  testsearch(0,@a);
#@a=(1..8000);  testsearch(0,@a);
#@a=(1..16000); testsearch(0,@a);

sub testsearch {
  my $deb=shift;
  my @a=@_;
  deb "----------\nArrsize: ".@a."\n";
  $deb and deb serialize(\@a,'a');

  my $time=time_fp;
  my @steps;
  my $ok=1;
  for(@a){
    my($res,$steps)=(binsearch($_,\@a),$Acme::Tools::Binsearch_steps);
    $ok=0 if $a[$res] !=$_;
    push @steps,$steps;
    #print "$_: ".binsearch($_,@a) ,"  steps=$steps\n";
  }
  ok($ok);
  $time=time_fp()-$time;
  print "Time: $time sek\n";
  print "Time pr search: ".($time/@a)." sek/search\n";
  print "Time pr step:   ".($time/sum(@steps))." sek/step\n";
  print "Steps:   sum = ".sum(@steps)."   avg = ".avg(@steps)."   min = ".min(@steps)."   max = ".max(@steps)."\n";
  if($deb){my %ant;$ant{$_}++ for @steps; print "Searches with $_ steps: $ant{$_}\n" for sort {$a<=>$b} keys %ant}
}

my $bs;
ok( binsearch(1,[1,2,5])==0 );
ok( binsearch(2,[1,2,5])==1 );
ok( binsearch(5,[1,2,5])==2 );
ok( ($bs=binsearch(6,[1,2,5],1))==2.5, "after $bs");
ok( ($bs=binsearch(3,[1,2,5],1))==1.5, $bs);
ok( ($bs=binsearch(1.4,[1,2,5],1))==0.5, $bs);
ok( ($bs=binsearch(0,[1,2,5],1))==-0.5,"before $bs");

my $cmpsub=sub{$_[0] <=> $_[1]};
ok( binsearch(1,[1,2,5],0,$cmpsub)==0 );
ok( binsearch(2,[1,2,5],0,$cmpsub)==1 );
ok( binsearch(5,[1,2,5],0,$cmpsub)==2 );
ok( ($bs=binsearch(6,[1,2,5],1,$cmpsub))==2.5, "after $bs");
ok( ($bs=binsearch(3,[1,2,5],1,$cmpsub))==1.5, $bs);
ok( ($bs=binsearch(1.4,[1,2,5],1,$cmpsub))==0.5, $bs);
ok( ($bs=binsearch(0,[1,2,5],1,$cmpsub))==-0.5,"before $bs");

ok( binsearch(10,[20,15,10,5],undef,sub{$_[1]<=>$_[0]}) == 2);       # 2 search arrays sorted numerically in opposite order
ok( binsearch("c",["a","b","c","d"],undef,sub{$_[0]cmp$_[1]}) == 2); # 2 search arrays sorted alphanumerically
ok( binsearchstr("b",["a","b","c","d"]) == 1);                       # 1 search arrays sorted alphanumerically

my @data=( map {  {num=>$_,sqrt=>sqrt($_), square=>$_**2}  } grep !($_%7), 1..10000  );
my($i1,$i2) = ( binsearch( {num=>8883}, \@data, undef, sub {$_[0]{num} <=> $_[1]{num}} ),
                binsearch( {num=>8883}, \@data, undef, 'num' )                             );
ok( $i1==1268, 'binsearch i1');
ok( $i2==1268, 'binsearch i2' );
#ok( $data[$i1]{square}==78907689 );
ok( $Acme::Tools::Binsearch_steps == 10, 'binsearch 10 steps' );
#print "i=$i   ".srlz(\$found,'f')."Binsearch_steps = $Acme::Tools::Binsearch_steps\n";

deb "--------------------------------------------------------------------------------eqarr\n";
ok( eqarr([1,2,3],[1,2,3],[1,2,3]) == 1 ,'eqarr 1');
ok( eqarr([1,2,3],[1,2,3],[1,2,4]) == 0 ,'eqarr 0');
ok( !defined(eqarr([1,2,3],[1,2,3,4]))  ,'eqarr undef' );
ok( do{eval{eqarr([1,2,3])};$@}            ,'eqarr croak 1');
ok( do{eval{eqarr([1,2,3],1,2,3)};$@}      ,'eqarr croak 2');

deb "--------------------------------------------------------------------------------rank\n";
ok( rank(1,[20,30,10,15,40])==10 ,'rank 1');
ok( rank(2,[20,30,10,15,40])==15 ,'rank 2');
ok( rank(3,[20,30,10,15,40])==20 ,'rank 3');
ok( rank(4,[20,30,10,15,40])==30 ,'rank 4.1');
ok( rank(4,[20,30,10,15,40,10])==20 ,'rank 4.2');

for my $big (0,2,20,200,2000){
  my $ant=min(20,$big);
  ok( eqarr([rank(20,[mix(1..$big)])],[1..$ant]), "rank wantarray $big");
  ok( eqarr([rankstr(20,[mix(1..$big)])],[(sort(1..$big))[0..$ant-1]]), "rankstr wantarray $big");

  ok( eqarr([rank(-20,[mix(1..$big)])],[reverse($big-$ant+1..$big)]), "rank wantarray neg $big");
  ok( eqarr([rankstr(-20,[mix(1..$big)])],[(reverse(sort(1..$big)))[0..$ant-1]]), "rankstr wantarray neg $big");

  #my @r20=rankstr(20,[mix(1..$big)]); deb join(",",@r20)."\n";
}


deb "--------------------------------------------------------------------------------pushsort\n";
my @p=(1..10);
pushsort @p,7;
ok( eqarr(  \@p,[1,2,3,4,5,6,7,7,8,9,10] ), 'pushsort '.join(",",@p) );

if($ENV{ATDEBUG}){
  my(@o,@n);my$i=0;
  require Benchmark; Benchmark::timethese(200,{
    'new' => sub{@n=();pushsort(@n,rand()) for 1..100},
    'old' => sub{@o=();pushsort(@o,rand()) for 1..100},
  });
  deb "len new=".@n." old=".@o."     sorted? new=".sorted(@n)." old=".sorted(@o)."\n";
}

@p=();
pushsort @p, rand for 1..1000;
ok( sorted(@p), 'pushsort' );
@p=();
pushsortstr @p, rand for 1..1000;
ok( sortedstr(@p), 'pushsortstr' );

deb "--------------------------------------------------------------------------------sorted\n";
my @num=sort {$a<=>$b} map rand()*100,1..100;
my @str=sort           map rand()*100,1..100;
ok( sorted(    @num ), 'sorted' );
ok( sortedstr( @str ), 'sortedstr' );
ok( !eqarr(\@num,\@str), 'sorted ne sortedstr' );

deb "--------------------------------------------------------------------------------sortby\n";
my @arr=(
   {Name=>'Alice', Year=>1970, Gender=>'F'},
   {Name=>'Bob',   Year=>1980, Gender=>'M'},
   {Name=>'Eve',   Year=>1990, Gender=>'F'},
   {Name=>'Adam',  Year=>1971, Gender=>'M'},
   {Name=>'Eva',   Year=>1972, Gender=>'F'},
   {Name=>'Nobby', Year=>1990, Gender=>'F'},
   {Name=>'Eve',   Year=>1990, Gender=>'F'},
);
ok(srlz([sortby(\@arr,'Year','Gender','Name')]),
   srlz([map$$_[0],
	 sort{$$a[1]cmp$$b[1]}
	 map[$_,sprintf("%-30s%04d%s",@$_{qw(Year Gender Name)})],
	 @arr]));



( run in 3.625 seconds using v1.01-cache-2.11-cpan-d8267643d1d )