/* Exercise mpz_*_kronecker_*() and mpz_jacobi() functions.
Copyright 1999-2004, 2013 Free Software Foundation, Inc.
This file is part of the GNU MP Library test suite.
The GNU MP Library test suite is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
The GNU MP Library test suite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
/* With no arguments the various Kronecker/Jacobi symbol routines are checked against some test data and a lot of derived data.
To check the test data against PARI-GP, run
t-jac -p | gp -q
Enhancements:
More big test cases than those given by check_squares_zi would be good. */
void
try_base (mp_limb_t a, mp_limb_t b, int answer)
{ int got;
if ((b & 1) == 0 || b == 1 || a > b) return;
got = mpn_jacobi_base (a, b, 0); if (got != answer)
{
printf (LL("mpn_jacobi_base (%lu, %lu) is %d should be %d\n", "mpn_jacobi_base (%llu, %llu) is %d should be %d\n"),
a, b, got, answer);
abort ();
}
}
void
try_zi_ui (mpz_srcptr a, unsignedlong b, int answer)
{ int got;
got = mpz_kronecker_ui (a, b); if (got != answer)
{
printf ("mpz_kronecker_ui (");
mpz_out_str (stdout, 10, a);
printf (", %lu) is %d should be %d\n", b, got, answer);
abort ();
}
}
void
try_zi_si (mpz_srcptr a, long b, int answer)
{ int got;
got = mpz_kronecker_si (a, b); if (got != answer)
{
printf ("mpz_kronecker_si (");
mpz_out_str (stdout, 10, a);
printf (", %ld) is %d should be %d\n", b, got, answer);
abort ();
}
}
void
try_ui_zi (unsignedlong a, mpz_srcptr b, int answer)
{ int got;
got = mpz_ui_kronecker (a, b); if (got != answer)
{
printf ("mpz_ui_kronecker (%lu, ", a);
mpz_out_str (stdout, 10, b);
printf (") is %d should be %d\n", got, answer);
abort ();
}
}
void
try_si_zi (long a, mpz_srcptr b, int answer)
{ int got;
got = mpz_si_kronecker (a, b); if (got != answer)
{
printf ("mpz_si_kronecker (%ld, ", a);
mpz_out_str (stdout, 10, b);
printf (") is %d should be %d\n", got, answer);
abort ();
}
}
/* Don't bother checking mpz_jacobi, since it only differs for b even, and we don't have an actual expected answer for it. tests/devel/try.c does
some checks though. */ void
try_zi_zi (mpz_srcptr a, mpz_srcptr b, int answer)
{ int got;
got = mpz_kronecker (a, b); if (got != answer)
{
printf ("mpz_kronecker (");
mpz_out_str (stdout, 10, a);
printf (", ");
mpz_out_str (stdout, 10, b);
printf (") is %d should be %d\n", got, answer);
abort ();
}
}
/* don't bother with these tests if they're only going to produce
even/even */ if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (a_period)) goto done;
for (i = 0; i < 6; i++)
{
mpz_add (a, a, a_period);
try_pn (a, b, answer);
}
mpz_set (a, a_orig); for (i = 0; i < 6; i++)
{
mpz_sub (a, a, a_period);
try_pn (a, b, answer);
}
done:
mpz_clear (a);
mpz_clear (a_period);
}
/* Try (a/b+k*p) for various k, using the fact (a/b) is periodic in b of period p.
period p a==0,1mod4 a a==2mod4 4*a a==3mod4 and b odd 4*a a==3mod4 and b even 8*a
In Henri Cohen's book the period is given as 4*a for all a==2,3mod4, but a counterexample would seem to be (3/2)=-1 which with (3/14)=+1 doesn't have period 4*a (but rather 8*a with (3/26)=-1). Maybe the plain 4*a is to be read as applying to a plain Jacobi symbol with b odd, rather than
the Kronecker extension to b even. */
void
try_periodic_den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
{
mpz_t b, b_period; int i;
/* don't bother with these tests if they're only going to produce
even/even */ if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (b_period)) goto done;
for (i = 0; i < 6; i++)
{
mpz_add (b, b, b_period);
try_pn (a, b, answer);
}
mpz_set (b, b_orig); for (i = 0; i < 6; i++)
{
mpz_sub (b, b, b_period);
try_pn (a, b, answer);
}
/* Try (a/b*2^k) for various k. */ void
try_2den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
{
mpz_t b; int kindex; int answer_a2, answer_k; unsignedlong k;
/* don't bother when b==0 */ if (mpz_sgn (b_orig) == 0) return;
mpz_init_set (b, b_orig);
/* (a/2) is 0 if a even, 1 if a==1 or 7 mod 8, -1 if a==3 or 5 mod 8 */
answer_a2 = (mpz_even_p (a) ? 0
: (((SIZ(a) >= 0 ? PTR(a)[0] : -PTR(a)[0]) + 2) & 7) < 4 ? 1
: -1);
for (kindex = 0; kindex < numberof (ktable); kindex++)
{
k = ktable[kindex];
/* Try (a*2^k/b) for various k. If it happens mpz_ui_kronecker() gets (2/b)
wrong it will show up as wrong answers demanded. */ void
try_2num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
{
mpz_t a; int kindex; int answer_2b, answer_k; unsignedlong k;
/* don't bother when a==0 */ if (mpz_sgn (a_orig) == 0) return;
mpz_init (a);
/* (2/b) is 0 if b even, 1 if b==1 or 7 mod 8, -1 if b==3 or 5 mod 8 */
answer_2b = (mpz_even_p (b) ? 0
: (((SIZ(b) >= 0 ? PTR(b)[0] : -PTR(b)[0]) + 2) & 7) < 4 ? 1
: -1);
for (kindex = 0; kindex < numberof (ktable); kindex++)
{
k = ktable[kindex];
/* The try_2num() and try_2den() routines don't in turn call try_periodic_num() and try_periodic_den() because it hugely increases the number of tests performed, without obviously increasing coverage.
/* special values inducing a==b==1 at the end of jac_or_kron() */
{ "0x10000000000000000000000000000000000000000000000001", "0x10000000000000000000000000000000000000000000000003", 1 },
/* Test for previous bugs in jacobi_2. */
{ "0x43900000000", "0x42400000439", -1 }, /* 32-bit limbs */
{ "0x4390000000000000000", "0x4240000000000000439", -1 }, /* 64-bit limbs */
/* Some tests involving large quotients in the continued fraction
expansion. */
{ "37200210845139167613356125645445281805", "451716845976689892447895811408978421929", -1 },
{ "67674091930576781943923596701346271058970643542491743605048620644676477275152701774960868941561652032482173612421015", "4902678867794567120224500687210807069172039735", 0 },
{ "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683283672592", "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683290481773", 1 },
/* Exercises the case asize == 1, btwos > 0 in mpz_jacobi. */
{ "804609", "421248363205206617296534688032638102314410556521742428832362659824", 1 } ,
{ "4190209", "2239744742177804210557442048984321017460028974602978995388383905961079286530650825925074203175536427000", 1 },
/* Exercises the case asize == 1, btwos = 63 in mpz_jacobi
(relevant when GMP_LIMB_BITS == 64). */
{ "17311973299000934401", "1675975991242824637446753124775689449936871337036614677577044717424700351103148799107651171694863695242089956242888229458836426332300124417011114380886016", 1 },
{ "3220569220116583677", "41859917623035396746", -1 },
/* Other test cases that triggered bugs during development. */
{ "37200210845139167613356125645445281805", "340116213441272389607827434472642576514", -1 },
{ "74400421690278335226712251290890563610", "451716845976689892447895811408978421929", -1 },
};
int i;
mpz_t a, b;
mpz_init (a);
mpz_init (b);
for (i = 0; i < numberof (data); i++)
{
mpz_set_str_or_abort (a, data[i].a, 0);
mpz_set_str_or_abort (b, data[i].b, 0);
try_all (a, b, data[i].answer);
}
mpz_clear (a);
mpz_clear (b);
}
/* (a^2/b)=1 if gcd(a,b)=1, or (a^2/b)=0 if gcd(a,b)!=1.
This includes when a=0 or b=0. */ void
check_squares_zi (void)
{
gmp_randstate_ptr rands = RANDS;
mpz_t a, b, g; int i, answer;
mp_size_t size_range, an, bn;
mpz_t bs;
/* Assumes that b = prod p_k^e_k */ int
ref_jacobi (mpz_srcptr a, mpz_srcptr b, unsigned nprime,
mpz_t prime[], unsigned *exp)
{ unsigned i; int res;
for (i = 0, res = 1; i < nprime; i++) if (exp[i])
{ int legendre = refmpz_legendre (a, prime[i]); if (!legendre) return 0; if (exp[i] & 1)
res *= legendre;
} return res;
}
/* These tests compute (a|n), where the quotient sequence includes large quotients, and n has a known factorization. Such inputs are generated as follows. First, construct a large n, as a power of a prime p of moderate size.
Next, compute a matrix from factors (q,1;1,0), with q chosen with uniformly distributed size. We must stop with matrix elements of roughly half the size of n. Denote elements of M as M = (m00, m01; m10, m11).
We now look for solutions to
n = m00 x + m01 y a = m10 x + m11 y
with x,y > 0. Since n >= m00 * m01, there exists a positive solution to the first equation. Find those x, y, and substitute in the second equation to get a. Then the quotient sequence for (a|n) is precisely the quotients used when constructing M, followed by the quotient sequence for (x|y).
Numbers should also be large enough that we exercise hgcd_jacobi, which means that they should be larger than
max (GCD_DC_THRESHOLD, 3 * HGCD_THRESHOLD)
With an n of roughly 40000 bits, this should hold on most machines.
*/
/* First generate a number with known factorization, as a random
smallish prime raised to an odd power. Then (a|n) = (a|p). */
mpz_rrandomb (p, rands, PBITS);
mpz_nextprime (p, p);
mpz_pow_ui (n, p, PPOWER);
nsize = mpz_sizeinbase (n, 2);
for (i = 0; i < COUNT; i++)
{ int answer;
mp_bitcnt_t msize;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.