diff --git a/CHANGES b/CHANGES index 3baf397..cb93ce0 100644 --- a/CHANGES +++ b/CHANGES @@ -140,6 +140,13 @@ * fixed a leak in _div() (Thanx Tassilo v. Parsival!) * put _div() into XS, making division slightly faster for small numbers * put leak.pl and leaktest into MANIFEST for later checking +2005-01-01 v1.17 Tels 5182 tests + * use XSLoader instead of DynaLoader to save a tiny amount of memory + * take over tests from Math::BigInt v1.74 + * require Math::BigInt v1.74 + * simplify sub code in XS (left-over artifact from v1.16) + * fix a leak in _zeros() + * _zeros() is now much faster for odd numbers (O(1) vs. O(N*N)) Please send me test-reports, your experiences with this and your ideas - I love to hear about my work! diff --git a/GMP.xs b/GMP.xs index 2f96c52..9916c91 100644 --- a/GMP.xs +++ b/GMP.xs @@ -151,6 +151,10 @@ _num(Class, n) ############################################################################## # _zeros() - return number of trailing zeros (in decimal form) +# This is costly, since it needs O(N*N) to convert the number to decimal, +# even though for most cases the number does not have many trailing zeros. +# For numbers longer than X digits (10?) we could divide repeatable by 1e5 +# or something and see if we get zeros. int _zeros(Class,n) @@ -163,30 +167,37 @@ _zeros(Class,n) char *buf_end; CODE: - /* len is always >= 1, and might be off (greater) by one than real len */ - len = mpz_sizeinbase(*n, 10); - TEMP = newSV(len); /* alloc len +1 bytes */ - SvPOK_on(TEMP); /* make an PV */ - buf = SvPVX(TEMP); /* get ptr to storage */ - buf_end = buf + len - 1; /* end of storage (-1)*/ - mpz_get_str(buf, 10, *n); /* convert to decimal string */ - RETVAL = 0; - if (*buf_end == 0) - { - buf_end--; /* ptr to last real digit */ - len --; /* got one shorter than expected */ - } - if (len > 1) /* '0' has not trailing zeross! */ + /* odd numbers can not have trailing zeros */ + RETVAL = 1 - mpz_tstbit(*n,0); + + if (RETVAL != 0) /* was even */ { - while (len-- > 0) + /* len is always >= 1, and might be off (greater) by one than real len */ + len = mpz_sizeinbase(*n, 10); + TEMP = newSV(len); /* alloc len +1 bytes */ + SvPOK_on(TEMP); /* make an PV */ + buf = SvPVX(TEMP); /* get ptr to storage */ + buf_end = buf + len - 1; /* end of storage (-1)*/ + mpz_get_str(buf, 10, *n); /* convert to decimal string */ + RETVAL = 0; + if (*buf_end == 0) /* points to terminating zero? */ { - if (*buf_end-- != '0') - { - break; - } - RETVAL++; + buf_end--; /* ptr to last real digit */ + len --; /* got one shorter than expected */ } - } + if (len > 1) /* '0' has not trailing zeross! */ + { + while (len-- > 0) /* actually, we should hit a nonzero */ + { /* before the end */ + if (*buf_end-- != '0') + { + break; + } + RETVAL++; + } + } + SvREFCNT_dec(TEMP); /* Bumpersticker: Free Temp! */ + } /* end if n was even */ OUTPUT: RETVAL @@ -359,19 +370,13 @@ _sub(Class,x,y, ...) PREINIT: mpz_t* TEMP; mpz_t* TEMP_1; - mpz_t* TEMP_2; PPCODE: GMP_GET_ARGS_0_1; /* (TEMP, TEMP_1) = (x,y) */ if ( items == 4 && SvTRUE(ST(3)) ) { - /* return new(y - x) */ - /* need to create TEMP_2 or it will ssegfault */ - TEMP_2 = malloc (sizeof(mpz_t)); mpz_init(*TEMP_2); - - mpz_sub(*TEMP_2, *TEMP, *TEMP_1); - - PUSHs(sv_setref_pv(sv_newmortal(), "Math::BigInt::GMP", (void*)TEMP_2)); - /*PUSHs(sv_setref_pv(y, "Math::BigInt::GMP", (void*)TEMP_2)); */ + /* y -= x */ + mpz_sub(*TEMP_1, *TEMP, *TEMP_1); + PUSHs( y ); } else { diff --git a/META.yml b/META.yml index 3b6394b..ae72393 100644 --- a/META.yml +++ b/META.yml @@ -1,11 +1,11 @@ --- #YAML:1.0 name: Math-BigInt-GMP -version: 1.16 +version: 1.17 version_from: lib/Math/BigInt/GMP.pm license: perl distribution_type: module -generated_by: Math-BigInt-GMP version 1.16 +generated_by: Math-BigInt-GMP version 1.17 installdirs: site requires: - Math::BigFloat: 1.47 - Math::BigInt: 1.73 + Math::BigInt: 1.74 + XSLoader: 0.02 diff --git a/Makefile.PL b/Makefile.PL index 0b0f51d..5ac308b 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -31,8 +31,8 @@ WriteMakefile( 'NAME' => 'Math::BigInt::GMP', 'VERSION_FROM' => 'lib/Math/BigInt/GMP.pm', # finds $VERSION 'PREREQ_PM' => { - Math::BigInt => 1.73, - Math::BigFloat => 1.47, + Math::BigInt => 1.74, + XSLoader => 0.02, }, 'LIBS' => ['-lgmp'], # e.g., '-lm' 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' diff --git a/NEW b/NEW index 052da82..b6d57fc 100644 --- a/NEW +++ b/NEW @@ -1,18 +1,27 @@ Changes between the last and this version: -v1.16: - * fixed a leak in _div() and simplified it (Thanx Tassilo v. Parseval) - * moved the _div() code to XS to make it a bit faster - * put leak.pl and leaktest into MANIFEST for later checking +v1.17: + * use XSLoader instead of DynaLoader to save a tiny amount of memory + * take over tests from Math::BigInt v1.74 + * require Math::BigInt v1.74 + * simplify sub code in XS (left-over artifact from v1.16) + * fix a leak in _zeros() + * _zeros() is now much faster for odd numbers (O(1) vs. O(N*N)) ############################################################################# -v1.15: - 221 / 444: 5 wallclock secs ( 5.20 usr + 0.01 sys = 5.21 CPU) @ 18940/s (n=98679) - 444 / 221: 6 wallclock secs ( 5.20 usr + 0.01 sys = 5.21 CPU) @ 19108/s (n=99555) - v1.16: - 221 / 444: 6 wallclock secs ( 5.24 usr + 0.01 sys = 5.25 CPU) @ 20957/s (n=110026) - 444 / 221: 5 wallclock secs ( 5.28 usr + 0.00 sys = 5.28 CPU) @ 21231/s (n=112102) + +Benchmark: running zeros(1.0x1000), zeros(123), zeros(1x1000) for at least 5 CPU seconds... +zeros(1.0x1000): 5s (5.02 usr + 0.15 sys = 5.17 CPU) @ 14179/s (n=73309) +zeros(123): 5s (5.19 usr + 0.11 sys = 5.30 CPU) @ 253584/s (n=1344000) +zeros(1x1000): 5s (5.06 usr + 0.17 sys = 5.23 CPU) @ 14106/s (n=73777) + + +v1.17: +Benchmark: running zeros(1.0x1000), zeros(123), zeros(1x1000) for at least 5 CPU seconds... +zeros(1.0x1000): 5s (5.06 usr + 0.15 sys = 5.21 CPU) @ 14160/s (n=73777) +zeros(123): 5s (5.27 usr + 0.01 sys = 5.28 CPU) @ 299044/s (n=1578957) +zeros(1x1000): 5s (5.21 usr + 0.01 sys = 5.22 CPU) @ 302482/s (n=1578957) diff --git a/SIGNATURE b/SIGNATURE index 52a2237..c1fc9cf 100644 --- a/SIGNATURE +++ b/SIGNATURE @@ -1,12 +1,12 @@ This file contains message digests of all files listed in MANIFEST, -signed via the Module::Signature module, version 0.41. +signed via the Module::Signature module, version 0.42. To verify the content in this distribution, first make sure you have Module::Signature installed, then type: % cpansign -v -It would check each file's integrity, as well as the signature's +It will check each file's integrity, as well as the signature's validity. If "==> Signature verified OK! <==" is not displayed, the distribution may already have been compromised, and you should not run its Makefile.PL or Build.PL. @@ -14,35 +14,35 @@ not run its Makefile.PL or Build.PL. -----BEGIN PGP SIGNED MESSAGE----- SHA1 70d6187d0152848c922dc4360fa6dd3a3dc35c62 BUGS -SHA1 3743ce85e7e98c882bd05ec9eebcfb31ff453815 CHANGES +SHA1 10ba246d1dbff89a3905428d6f76f42aef36579a CHANGES SHA1 dda5ca4f413031e9efcaa1600461d5e2adaa3a40 CREDITS -SHA1 636480140c61a18f193b0178dc9809c295d9456a GMP.xs +SHA1 c6b4374d7e911bd399534af9fa5ceb8c90dc6485 GMP.xs SHA1 1c219a49ee07891ca39de3f89ce4bbe02549af82 INSTALL SHA1 d6a6c30ee6d9ba6b9afab8bbf6a25e1b23c744e0 LICENSE SHA1 6cd50151e6eab24927bce91ec062e6d71724ce63 MANIFEST -SHA1 9c0c8cf77b1ce503893fba602c9ea48cb1d996b9 META.yml -SHA1 185af48c59491c5e3351c6d9950c3565de74005a Makefile.PL -SHA1 704f02fad759cc0d99558352f5a7cfb7d8c11b1e NEW +SHA1 8b0a5a75c4530c61658e4af1cd76420270023e19 META.yml +SHA1 83262bb7cc34f4016ed89005e3b0d93438963f31 Makefile.PL +SHA1 2be04f1ccd8a14a7e00e99ce661a47e579f9f02f NEW SHA1 e9de29b6e5e9a5e446231b5b12b644f6ed2caafc README -SHA1 e4fd0b099ed6ef332c72cbf85719a7cf1bd2dc6a TODO +SHA1 200ade10e14449652ac59d0c8a9569cf29645cbd TODO SHA1 fd48d0d8750eb949e485d8136b5b424fe73e9775 build/README -SHA1 c93694211f8ba09c49ae69b5f3fd4d957bd26f62 build/leak.pl +SHA1 7bcc4113830721ad6e37a1ea79df94a6987c836d build/leak.pl SHA1 ac25bda8a6eb9058a9e42a8943c3e11b9fed88dc build/leaktest -SHA1 bed207cfb72446fcb746c8d438538b6801a181fd lib/Math/BigInt/GMP.pm -SHA1 7704eb924e8a297edafa95c5075df502bbc2f14a t/bigfltpm.inc -SHA1 3287807111be40445e3f8ed5cb1f738996e2b18d t/bigfltpm.t -SHA1 b0f41f0025528cfea909c9a212c2e377ee3d9243 t/bigintg.t -SHA1 43b2f324aa16df6865272c192bcab9f25bf7008e t/bigintpm.inc +SHA1 103f5b902922eba6550271837d8d64d6c40d73d7 lib/Math/BigInt/GMP.pm +SHA1 57a416650fede5f54aa295e5cd133022a0b9efdd t/bigfltpm.inc +SHA1 ba0b4085ef17b06a733d7ee26cb5b54ecf4c6094 t/bigfltpm.t +SHA1 d552991e5df86d3f04b6928c97efe2653fc776d2 t/bigintg.t +SHA1 aaaea1e9f34d1dfe090911863e5289f85f83ed46 t/bigintpm.inc SHA1 6dfbf7bc6601b23073204e9c104d3b68213c93ab t/bigintpm.t SHA1 f7aad87c0a30330d474f4fb45f6d1953d6701d2f typemap -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (GNU/Linux) -iQEVAwUBQboC9XcLPEOTuEwVAQFPLQf+Olfms17l/g4dhwcRpRLtaAm525xWEtiV -ARQnCf/xIYfhmDR4deih71aDX6PXjRjihukU+OtPIMdE6MyHUUbzvNqGa0waPIor -O+eOqZlZnyjJLvFGKZXJJtFF39M0ZSzmrMh9wuYvRzQhdKNXgqCju20Ni9puw6IA -tD+V7Y0I5FkXJOCewy8NECoXnQjlcSAiWHZRsByDkJSLA6pBtoQUXuzN73D8I1P/ -JEOuQTQ0ZlF+kFs9wSShOoYYc16OS/EGcBWHw8F8jdzENErmUZ/RP7E9E4fMewey -0MnJ9V2gRHu5Qe8oaoQs8UcaqrWOE5QG/bhW7rcXCVRL4RxNXv0iTw== -=GgRM +iQEVAwUBQdbBZXcLPEOTuEwVAQGaAwf8DE9+TD70VMuSB8qPkutFHacs2Z1ztUGf +pqNMNtKi/Y6W7gY0zyQbp7nqwX8oR2Dcx5ULi1UuIM3MzIaDlB/se0ThEqsd+No4 +a9pjBxqnQ3zDisFCqtsEWsEmvBYu7JUH2y4ZSe46p2qfm/UYGFBXzjm9PXXpVQyn +JU/0GxsQrhfZBnEIKT4KbPzDKp1oPLw0gf41+Zmh6clix4hp5i0zUNycwSX9nUWV +KNVpO41KgMDjZURTRazFbZgz+DgIymvdgp8yCTNv5DGLTfhNpS0c0hj6EyVmXnTQ +iiX+YLRUkwr2yLfKwLN4p2kk4KO7rL9oA9M9AHS/y8/cqvidUiXuCQ== +=bjyF -----END PGP SIGNATURE----- diff --git a/TODO b/TODO index f9f41d9..9f7c8f4 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ * _lsft() and _rsft() could probably be a bit more optimized * move _log_int() to XS -* move sub() and div() completely to XS ? * _digit() and _len() could be more optimized * _zeros() could be more optimized (divide by 1e5, check for == 0?) * replace all malloc() with New() and all free() with Savefree()? diff --git a/build/leak.pl b/build/leak.pl index 275e44d..1cbe60c 100644 --- a/build/leak.pl +++ b/build/leak.pl @@ -29,11 +29,12 @@ [ sub { my $z = $x; $z %= $y; 1; }, '%=' ], [ sub { my $z = $x; $z /= $y; 1; }, '/=' ], [ sub { my ($q,$r) = $x->copy()->bdiv($y); 1; }, '(q,r) = x / y' ], + [ sub { $x->_trailing_zeros(); }, '_zeros(x)' ], # needs an even number! ) { my $handle; my $count = Devel::Leak::NoteSV($handle); - for (1..10) { &{$do->[0]}; } + for (1..13) { &{$do->[0]}; } print "$do->[1] leaked ", Devel::Leak::CheckSV($handle) - $count, " things\n"; } diff --git a/lib/Math/BigInt/GMP.pm b/lib/Math/BigInt/GMP.pm index af67c6a..3a3f414 100644 --- a/lib/Math/BigInt/GMP.pm +++ b/lib/Math/BigInt/GMP.pm @@ -7,14 +7,12 @@ use strict; use 5.005; # use warnings; # dont use warnings for older Perls -require Exporter; -require DynaLoader; +use vars qw/$VERSION/; -use vars qw/@ISA $VERSION/; -@ISA = qw(Exporter DynaLoader); -$VERSION = '1.16'; +$VERSION = '1.17'; -bootstrap Math::BigInt::GMP $VERSION; +use XSLoader; +XSLoader::load "Math::BigInt::GMP", $VERSION; sub import { } # catch and throw away sub api_version() { 1; } # we are compatible with MBI v1.70 and up diff --git a/t/bigfltpm.inc b/t/bigfltpm.inc index 131e453..5f27a8b 100644 --- a/t/bigfltpm.inc +++ b/t/bigfltpm.inc @@ -4,6 +4,8 @@ ok ($class->config()->{lib},$CL); use strict; +my $z; + while () { chomp; @@ -87,7 +89,27 @@ while () else { $try .= "\$y = $class->new(\"$args[1]\");"; - if ($f eq "fcmp") { + + if ($f eq "bgcd") + { + if (defined $args[2]) + { + $try .= " \$z = $class->new(\"$args[2]\"); "; + } + $try .= "$class\::bgcd(\$x, \$y"; + $try .= ", \$z" if (defined $args[2]); + $try .= " );"; + } + elsif ($f eq "blcm") + { + if (defined $args[2]) + { + $try .= " \$z = $class->new(\"$args[2]\"); "; + } + $try .= "$class\::blcm(\$x, \$y"; + $try .= ", \$z" if (defined $args[2]); + $try .= " );"; + } elsif ($f eq "fcmp") { $try .= '$x <=> $y;'; } elsif ($f eq "facmp") { $try .= '$x->facmp($y);'; @@ -115,6 +137,7 @@ while () } # print "# Trying: '$try'\n"; $ans1 = eval $try; + print "# Error: $@\n" if $@; if ($ans =~ m|^/(.*)$|) { my $pat = $1; @@ -337,6 +360,42 @@ sub ok_undef } __DATA__ +&bgcd +inf:12:NaN +-inf:12:NaN +12:inf:NaN +12:-inf:NaN +inf:inf:NaN +inf:-inf:NaN +-inf:-inf:NaN +abc:abc:NaN +abc:+0:NaN ++0:abc:NaN ++0:+0:0 ++0:+1:1 ++1:+0:1 ++1:+1:1 ++2:+3:1 ++3:+2:1 +-3:+2:1 +-3:-2:1 +-144:-60:12 +144:-60:12 +144:60:12 +100:625:25 +4096:81:1 +1034:804:2 +27:90:56:1 +27:90:54:9 +&blcm +abc:abc:NaN +abc:+0:NaN ++0:abc:NaN ++0:+0:NaN ++1:+0:0 ++0:+1:0 ++27:+90:270 ++1034:+804:415668 $div_scale = 40; &flog 0::NaN @@ -1479,7 +1538,7 @@ abc:0 1200:1 -1200:1 &is_positive -0:1 +0:0 1:1 -1:0 -123:0 diff --git a/t/bigfltpm.t b/t/bigfltpm.t index 60926bc..c32a12e 100755 --- a/t/bigfltpm.t +++ b/t/bigfltpm.t @@ -9,7 +9,7 @@ BEGIN unshift @INC, '../lib'; # for running manually unshift @INC, '../blib/arch'; chdir 't' if -d 't'; - plan tests => 1924; + plan tests => 1992; } use Math::BigInt lib => 'GMP'; diff --git a/t/bigintg.t b/t/bigintg.t index 5ca2055..c403964 100755 --- a/t/bigintg.t +++ b/t/bigintg.t @@ -9,7 +9,7 @@ BEGIN chdir 't' if -d 't'; unshift @INC, '../lib'; # for running manually unshift @INC, '../blib/arch'; # for running manually - plan tests => 286; + plan tests => 288; } use Math::BigInt::GMP; @@ -154,6 +154,8 @@ foreach (qw/ 1 12 123 1234 12345 123456 1234567 12345678 123456789/) $x = $C->_new("1256000000"); ok ($C->_zeros($x),6); $x = $C->_new("152"); ok ($C->_zeros($x),0); $x = $C->_new("123000"); ok ($C->_zeros($x),3); +$x = $C->_new("123001"); ok ($C->_zeros($x),0); +$x = $C->_new("1"); ok ($C->_zeros($x),0); $x = $C->_new("0"); ok ($C->_zeros($x),0); # _lsft, _rsft diff --git a/t/bigintpm.inc b/t/bigintpm.inc index 6453879..4a8a663 100644 --- a/t/bigintpm.inc +++ b/t/bigintpm.inc @@ -778,7 +778,7 @@ inf:inf:NaN -inf:1 NaNneg:0 &is_positive -0:1 +0:0 -1:0 1:1 +inf:1