There were two kinds of improvements: providing the 3-argument operators (i.e. uint128_add($to, $a, $b)) and optimizing the SV to int128_t conversions.
I think I got the first part handled ok - but I haven't given consideration to the second. For the record, my "rough estimation script" (for multiplication only) is as follows - in accordance with the usual mantra that I follow when creating objects:
package Sis::UInt128;
use warnings;
use strict;
use Math::GMPz qw(:mpz);
use Benchmark qw(:all);
use Inline C => Config =>
BUILD_NOISY => 1,
TYPEMAPS => ['./typemap_128'],
USING => 'ParseRegExp';
use Inline C => <<'EOC';
SV * create() {
__uint128 *ps;
SV * obj_ref, * obj;
New(42, ps, 1, __uint128);
if(ps == NULL) croak("Failed to allocate memory in create functio
+n");
obj_ref = newSV(0);
obj = newSVrv(obj_ref, "Sis::UInt128");
sv_setiv(obj, INT2PTR(IV,ps));
SvREADONLY_on(obj);
return obj_ref;
}
void _assign(__uint128 * rop, SV * h, SV * l) {
__uint128 __div = 9223372036854775808ULL;
unsigned __int64 high, low;
high = (unsigned __int64)SvUV(h);
low = (unsigned __int64)SvUV(l);
*rop = ((__uint128)__div * high) + (__uint128)low;
}
void _deref_obj(__uint128 * obj) {
dXSARGS;
__uint128 __div = 9223372036854775808ULL;
ST(0) = sv_2mortal(newSVuv(*obj / __div));
ST(1) = sv_2mortal(newSVuv(*obj % __div));
XSRETURN(2);
}
void DESTROY(__uint128 * obj) {
printf("Cleaning up\n");
Safefree(obj);
}
void mul_128(__uint128 * rop, __uint128 * op1, __uint128 * op2) {
*rop = *op1 * *op2;
}
EOC
our $mpz1 = Math::GMPz->new('676469752303423489');
our $mpz2 = Math::GMPz->new('776469752999423489');
our $mpz_ret = Math::GMPz::Rmpz_init2(128);
our $i_ret = create();
our $i_1 = create();
our $i_2 = create();
assign($i_1, "$mpz1");
assign($i_2, "$mpz2");
our $count = 50000;
timethese($count * 19, {
'mul_128' => 'mul_128($i_ret, $i_1, $i_2)',
'gmpz' => 'Math::GMPz::Rmpz_mul($mpz_ret, $mpz1, $mpz2)',
});
print retrieve($i_1),"\n", retrieve($i_2),"\n", retrieve($i_ret), "\n"
+;
print "$mpz1\n$mpz2\n$mpz_ret\n";
sub assign {
my $obj = shift;
my $num = shift;
my @args;
my $a0 = Math::GMPz->new($num) / 9223372036854775808;
my $a1 = Math::GMPz->new($num) % 9223372036854775808;
$args[0] = "$a0" + 0;
$args[1] = "$a1" + 0;
_assign($obj, $args[0], $args[1]);
}
sub retrieve {
my @in = _deref_obj($_[0]);
my $num = Math::GMPz->new($in[0]);
$num *= 9223372036854775808;
$num += $in[1];
return "$num";
}
with a "typemap_128" that looks like this:
__uint128 * UI128
INPUT
UI128
$var = INT2PTR($type, SvIV(SvRV($arg)))
Cheers, Rob
|