Skip Menu |

This queue is for tickets about the Math-GMP CPAN distribution.

Report information
The Basics
Id: 118816
Status: resolved
Priority: 0/
Queue: Math-GMP

People
Owner: Nobody in particular
Requestors: HVDS [...] cpan.org
Cc: slaven [...] rezic.de
AdminCc:

Bug Information
Severity: (no value)
Broken in: 2.12
Fixed in: (no value)



CC: slaven [...] rezic.de
Subject: brootrem test failure in 2.12
As shown by test failures in http://www.cpantesters.org/cpan/report/3c9262e4-a6b0-11e6-a597-88fd411d5d86, versions of libgmp before 5.1 have a bug in mpz_rootrem when dealing with negative numbers. Attached 3 proposed patches: 0001-brootrem-work-around-bug-in-older-versions-of-libgmp.patch - Handle negative numbers explicitly if running against an older libgmp. This involves a check every time, but I think the checking is fast enough compared to the cost of the function itself. (I originally wrote it as a compile-time version check, but it would have caused problems if libgmp got downgraded after build.) 0002-Add-_gmp_build_version-and-_gmp_lib_version.patch - These feel like useful functions to have. Even better would be to report them automatically in smoke reports, but I'm not sure how to do that. I'm also not sure if a vstring is the ideal way to expose them, or if documenting them is useful. 0003-additional-test-for-root-of-negative.patch - As far as I can see the libgmp bug affected only mpz_rootrem, not mpz_root. But we should have a test for the case anyway. Hugo
Subject: 0001-brootrem-work-around-bug-in-older-versions-of-libgmp.patch
From a56c5297a684820a70821a7e777e166f5ae2f5d1 Mon Sep 17 00:00:00 2001 From: Hugo van der Sanden <hv@crypt.org> Date: Thu, 17 Nov 2016 15:01:31 +0000 Subject: [PATCH 1/3] brootrem: work around bug in older versions of libgmp The intent is that ($root, $remainder) = $x->brootrem($y) should return $root = trunc($x ** (1/$y)), but versions before libgmp-5.1 returned floor() instead of trunc() (ie rounded towards -inf rather than towards 0). Add code to work around this where needed. --- GMP.xs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/GMP.xs b/GMP.xs index 83ddea8..a79d55d 100644 --- a/GMP.xs +++ b/GMP.xs @@ -32,6 +32,28 @@ Durham, NC 27713 #define SWAP_GMP if (swap) { mpz_t* t = m; m = n; n = t; } +/* + * mpz_rootrem() has bug with negative first argument before 5.1.0 + */ +static int need_rootrem_workaround(mpz_t* m, unsigned long n) { + /* workaround only valid for n odd (n even should be an error) */ + if ((n & 1) == 0) + return 0; + + /* workaround only relevant for m negative */ + if (mpz_sgn(*m) >= 0) + return 0; + + /* workaround only needed for gmp_version < 5.1.0 */ + if ((gmp_version[0] && gmp_version[1] != '.') /* >= 10.0.0 */ + || (gmp_version[0] > '5') /* >= 6.0.0 */ + || (gmp_version[0] == '5' && gmp_version[2] != '0') /* >= 5.1.0 */ + ) + return 0; + + return 1; +} + static int not_here(char *s) { @@ -602,7 +624,17 @@ brootrem(m,n) remainder = malloc (sizeof(mpz_t)); mpz_init(*root); mpz_init(*remainder); - mpz_rootrem(*root, *remainder, *m, n); + if (need_rootrem_workaround()) { + /* Older libgmp have bugs for negative m, but if we need to we can + * work on abs(m) then negate the results. + */ + mpz_neg(*root, *m); + mpz_rootrem(*root, *remainder, *root, n); + mpz_neg(*root, *root); + mpz_neg(*remainder, *remainder); + } else { + mpz_rootrem(*root, *remainder, *m, n); + } EXTEND(SP, 2); PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)root)); PUSHs(sv_setref_pv(sv_newmortal(), "Math::GMP", (void*)remainder)); -- 2.10.2
Subject: 0002-Add-_gmp_build_version-and-_gmp_lib_version.patch
From 2fdfe94625a9223ae9917e4c72618c3d68512ec5 Mon Sep 17 00:00:00 2001 From: Hugo van der Sanden <hv@crypt.org> Date: Thu, 17 Nov 2016 15:05:43 +0000 Subject: [PATCH 2/3] Add _gmp_build_version() and _gmp_lib_version() This exposes the version of libgmp against which the module has been built, and the version against which it is now running. --- GMP.xs | 20 ++++++++++++++++++++ lib/Math/GMP.pm | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/GMP.xs b/GMP.xs index a79d55d..daf0c31 100644 --- a/GMP.xs +++ b/GMP.xs @@ -141,6 +141,26 @@ destroy(n) free(n); SV * +_gmp_build_version() + CODE: + char buf[] = STRINGIFY(__GNU_MP_VERSION) + "." STRINGIFY(__GNU_MP_VERSION_MINOR) + "." STRINGIFY(__GNU_MP_VERSION_PATCHLEVEL); + RETVAL = newSV(6); + scan_vstring(buf, buf + sizeof(buf), RETVAL); + OUTPUT: + RETVAL + +SV * +_gmp_lib_version() + CODE: + const char* v = gmp_version; + RETVAL = newSV(6); + scan_vstring(v, v + strlen(v), RETVAL); + OUTPUT: + RETVAL + +SV * stringify(n) mpz_t * n diff --git a/lib/Math/GMP.pm b/lib/Math/GMP.pm index e9e7cc6..7da533b 100644 --- a/lib/Math/GMP.pm +++ b/lib/Math/GMP.pm @@ -452,6 +452,26 @@ Returns the size of $x in base $plain_int_base . Returns the value of the object as an unblessed (and limited-in-precision) integer. +=head2 _gmp_build_version() + + my $gmp_version = Math::GMP::_gmp_build_version; + if ($gmp_version ge 6.0.0) { + print "Math::GMP was built against libgmp-6.0.0 or later"; + } + +Class method that returns as a vstring the version of libgmp against which +this module was built. + +=head2 _gmp_lib_version() + + my $gmp_version = Math::GMP::_gmp_lib_version; + if ($gmp_version ge 6.0.0) { + print "Math::GMP is now running with libgmp-6.0.0 or later"; + } + +Class method that returns as a vstring the version of libgmp it is currently +running. + =head2 gcd() An alias to bgcd() . -- 2.10.2
Subject: 0003-additional-test-for-root-of-negative.patch
From fabe2c8709a7deb169ce8bc4b9d2311690747e3e Mon Sep 17 00:00:00 2001 From: Hugo van der Sanden <hv@crypt.org> Date: Thu, 17 Nov 2016 15:57:59 +0000 Subject: [PATCH 3/3] additional test for root of negative Verify that broot() doesn't have the same problem with negative numbers that brootrem() had. --- t/01_gmppm.t | 1 + 1 file changed, 1 insertion(+) diff --git a/t/01_gmppm.t b/t/01_gmppm.t index 09d7e24..5f5113e 100644 --- a/t/01_gmppm.t +++ b/t/01_gmppm.t @@ -628,6 +628,7 @@ babcdefgh,36:808334348993 16:i4:2 999:i3:9 -1:i3:-1 +-2:i3:-1 &rootrem 16:i2:L4,0 999:i3:L9,270 -- 2.10.2
On Thu Nov 17 12:07:04 2016, HVDS wrote: Show quoted text
> As shown by test failures in > http://www.cpantesters.org/cpan/report/3c9262e4-a6b0-11e6-a597- > 88fd411d5d86, versions of libgmp before 5.1 have a bug in mpz_rootrem > when dealing with negative numbers. > > Attached 3 proposed patches: > > 0001-brootrem-work-around-bug-in-older-versions-of-libgmp.patch > - Handle negative numbers explicitly if running against an older > libgmp. This involves a check every time, but I think the checking is > fast enough compared to the cost of the function itself. (I originally > wrote it as a compile-time version check, but it would have caused > problems if libgmp got downgraded after build.) > > 0002-Add-_gmp_build_version-and-_gmp_lib_version.patch > - These feel like useful functions to have. Even better would be to > report them automatically in smoke reports, but I'm not sure how to do > that. I'm also not sure if a vstring is the ideal way to expose them, > or if documenting them is useful. > > 0003-additional-test-for-root-of-negative.patch > - As far as I can see the libgmp bug affected only mpz_rootrem, not > mpz_root. But we should have a test for the case anyway. > > Hugo
Hi Hugo! Sorry for the late reply, but using rt.cpan.org frustrates me because it keeps forgetting my login. I applied your patches (modified to be compiled) in version 2.13 which I uploaded to CPAN now. Thanks! Closing.