Math:Int128 didn't work out for me under Strawberry PERL.The build tests failed during compilation. Anyway I came up with the following.
use strict;
use Benchmark::Timer;
use Math::BigInt;
our $twoto32=Math::BigInt->bone();
$twoto32 <<= 32;
our $twoto64=Math::BigInt->bone();
$twoto64 <<= 64;
my $t=Benchmark::Timer->new();
$t->start('overall');
for (my $j=10000;$j<100000;$j++) {
my $test_address='0x'.'ABCD' x 6 . '123'.$j;
#my $test_address='0x'.'4142' x 6 . '30313233'; # check for bit and by
+te order => ascii "ABABABABABAB0123"
$t->start('new_bigint');
my $bigint=Math::BigInt->new($test_address);
$t->stop('new_bigint');
$t->start('convert_to');
my $binary16=bigint_to_varbinary16( $bigint);
#print "binary16".$binary16." length ".length($binary16)."\n";
$t->stop('convert_to');
$t->start('convert_from');
my $bigint2= varbinary16_to_bigint($binary16);
$t->stop('convert_from');
$t->start('convert_to_64bit');
my $binary16=bigint_to_varbinary16_64bit( $bigint);
#print "binary16".$binary16." length ".length($binary16)."\n";
$t->stop('convert_to_64bit');
$t->start('convert_from_64bit');
my $bigint2= varbinary16_to_bigint_64bit($binary16);
$t->stop('convert_from_64bit');
#print $bigint." ".$bigint2."\n";
}
$t->stop('overall');
print $t->reports;
exit 0;
sub bigint_to_varbinary16 {
my $bigint = shift;
my $my_copy=$bigint->copy(); # create a new bigint that can get mung
+ed
my @oa; #output array
my $i=4;
while($i>1) {
$i--;
#my ($q,$r) = $my_copy->brsft(32); # shift off 4 octets on the rig
+ht. In my install $r is NOT set!
my ($q,$r) = $my_copy->bdiv($twoto32); # shift off 4 octets on the
+ right
$oa[$i]= pack 'N',$r; # 32 bits in network bit order (MSB first)
if ($i==1) {
$oa[0]= pack 'N',$q; # saves one bdiv
last;
}
}
return join('',@oa);
}
sub varbinary16_to_bigint {
my $binary16=shift;
my $result = Math::BigInt->new(0);
my $i=0;
my $p=0;
while ($i<4) {
$result <<= 32 if $i>0; #!4294967296;
$result += unpack ('N', substr $binary16, $p , 4);
$p+=4;
$i++;
} ;
return $result;
}
sub bigint_to_varbinary16_64bit {
my $bigint = shift;
my $my_copy=$bigint->copy(); # create a new bigint that can get mung
+ed
my ($q,$r) = $my_copy->bdiv($twoto64); # shift off 8 octets on the r
+ight. brsft does not set remainder on my test machine, hence bdiv
return reverse join('', pack('Q',$r), pack('Q',$q)); # Q is little e
+ndian on my machine. I want DB SELECT to also be able to perform comp
+arison operators.
}
sub varbinary16_to_bigint_64bit {
my $binary16=shift;
my $string = reverse $binary16;
my $result = Math::BigInt->bzero();
$result += unpack ('Q', substr $string, 8 , 8);
$result <<= 64;
$result += unpack ('Q', substr $string, 0 , 8);
return $result;
}
Unsurprisingly, 64 bit pack and unpack is more efficient. I just wish there was an equivalent built in BigInt function to do this, and this was also built into DBI. But I ain't got time/skills to do that so I'll have to roll my own.
results:
new_bigint90000 trials of new_bigint (4.193s total), 46us/trial
convert_to90000 trials of convert_to (17.848s total), 198us/trial
convert_from90000 trials of convert_from (31.125s total), 345us/trial
convert_to_64bit90000 trials of convert_to_64bit (7.648s total), 84us/
+trial
convert_from_64bit90000 trials of convert_from_64bit (13.012s total),1
+44us/trial
|