version 1.1.1.1, 2000/09/09 14:12:25 |
version 1.1.1.2, 2003/08/25 16:06:20 |
|
|
/* mpn_jacobi_base -- limb/limb Jacobi symbol with restricted arguments. |
/* mpn_jacobi_base -- limb/limb Jacobi symbol with restricted arguments. |
|
|
THIS INTERFACE IS PRELIMINARY AND MIGHT DISAPPEAR OR BE SUBJECT TO |
THIS INTERFACE IS PRELIMINARY AND MIGHT DISAPPEAR OR BE SUBJECT TO |
INCOMPATIBLE CHANGES IN A FUTURE RELEASE OF GMP. */ |
INCOMPATIBLE CHANGES IN A FUTURE RELEASE OF GMP. |
|
|
/* |
Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
Copyright (C) 1999, 2000 Free Software Foundation, Inc. |
|
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
Line 21 License for more details. |
|
Line 20 License for more details. |
|
You should have received a copy of the GNU Lesser General Public License |
You should have received a copy of the GNU Lesser General Public License |
along with the GNU MP Library; see the file COPYING.LIB. If not, write to |
along with the GNU MP Library; see the file COPYING.LIB. If not, write to |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
MA 02111-1307, USA. */ |
|
|
#include "gmp.h" |
#include "gmp.h" |
#include "gmp-impl.h" |
#include "gmp-impl.h" |
#include "longlong.h" |
#include "longlong.h" |
|
|
|
|
#if COUNT_TRAILING_ZEROS_TIME <= 7 |
/* Use the simple loop by default. The generic count_trailing_zeros is not |
/* If count_trailing_zeros is fast, use it. |
very fast, and the extra trickery of method 3 has proven to be less use |
K7 at 7 cycles and P6 at 2 are good here. K6 at 12-27 and P5 at 18-42 |
than might have been though. */ |
are not. The default 15 in longlong.h is meant to mean not good here. */ |
#ifndef JACOBI_BASE_METHOD |
|
#define JACOBI_BASE_METHOD 2 |
|
#endif |
|
|
|
|
|
/* Use count_trailing_zeros. */ |
|
#if JACOBI_BASE_METHOD == 1 |
#define PROCESS_TWOS_ANY \ |
#define PROCESS_TWOS_ANY \ |
{ \ |
{ \ |
mp_limb_t twos; \ |
mp_limb_t twos; \ |
Line 40 MA 02111-1307, USA. */ |
|
Line 44 MA 02111-1307, USA. */ |
|
result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b); \ |
result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b); \ |
a >>= twos; \ |
a >>= twos; \ |
} |
} |
|
|
#define PROCESS_TWOS_EVEN PROCESS_TWOS_ANY |
#define PROCESS_TWOS_EVEN PROCESS_TWOS_ANY |
|
#endif |
|
|
#else |
/* Use a simple loop. A disadvantage of this is that there's a branch on a |
/* Use a loop instead. With "a" uniformly distributed there will usually be |
50/50 chance of a 0 or 1 low bit. */ |
only a few trailing zeros. |
#if JACOBI_BASE_METHOD == 2 |
|
|
Unfortunately the branch for the while loop here will be on a 50/50 |
|
chance of a 1 or 0, which is bad for branch prediction. */ |
|
|
|
#define PROCESS_TWOS_EVEN \ |
#define PROCESS_TWOS_EVEN \ |
{ \ |
{ \ |
int two; \ |
int two; \ |
two = JACOBI_TWO_U_BIT1 (b); \ |
two = JACOBI_TWO_U_BIT1 (b); \ |
do \ |
do \ |
{ \ |
{ \ |
a >>= 1; \ |
a >>= 1; \ |
result_bit1 ^= two; \ |
result_bit1 ^= two; \ |
ASSERT (a != 0); \ |
ASSERT (a != 0); \ |
} \ |
} \ |
while ((a & 1) == 0); \ |
while ((a & 1) == 0); \ |
} |
} |
|
|
#define PROCESS_TWOS_ANY \ |
#define PROCESS_TWOS_ANY \ |
if ((a & 1) == 0) \ |
if ((a & 1) == 0) \ |
PROCESS_TWOS_EVEN; |
PROCESS_TWOS_EVEN; |
|
#endif |
|
|
|
/* Process one bit arithmetically, then a simple loop. This cuts the loop |
|
condition down to a 25/75 chance, which should branch predict better. |
|
The CPU will need a reasonable variable left shift. */ |
|
#if JACOBI_BASE_METHOD == 3 |
|
#define PROCESS_TWOS_EVEN \ |
|
{ \ |
|
int two, mask, shift; \ |
|
\ |
|
two = JACOBI_TWO_U_BIT1 (b); \ |
|
mask = (~a & 2); \ |
|
a >>= 1; \ |
|
\ |
|
shift = (~a & 1); \ |
|
a >>= shift; \ |
|
result_bit1 ^= two ^ (two & mask); \ |
|
\ |
|
while ((a & 1) == 0) \ |
|
{ \ |
|
a >>= 1; \ |
|
result_bit1 ^= two; \ |
|
ASSERT (a != 0); \ |
|
} \ |
|
} |
|
#define PROCESS_TWOS_ANY \ |
|
{ \ |
|
int two, mask, shift; \ |
|
\ |
|
two = JACOBI_TWO_U_BIT1 (b); \ |
|
shift = (~a & 1); \ |
|
a >>= shift; \ |
|
\ |
|
mask = shift << 1; \ |
|
result_bit1 ^= (two & mask); \ |
|
\ |
|
while ((a & 1) == 0) \ |
|
{ \ |
|
a >>= 1; \ |
|
result_bit1 ^= two; \ |
|
ASSERT (a != 0); \ |
|
} \ |
|
} |
#endif |
#endif |
|
|
|
|
Line 74 MA 02111-1307, USA. */ |
|
Line 115 MA 02111-1307, USA. */ |
|
with a restricted range of inputs accepted, namely b>1, b odd, and a<=b. |
with a restricted range of inputs accepted, namely b>1, b odd, and a<=b. |
|
|
The initial result_bit1 is taken as a parameter for the convenience of |
The initial result_bit1 is taken as a parameter for the convenience of |
mpz_kronecker_zi_ui() et al. The sign changes both here and in those |
mpz_kronecker_ui() et al. The sign changes both here and in those |
routines accumulate nicely in bit 1, see the JACOBI macros. |
routines accumulate nicely in bit 1, see the JACOBI macros. |
|
|
The return value here is the normal +1, 0, or -1. Note that +1 and -1 |
The return value here is the normal +1, 0, or -1. Note that +1 and -1 |
Line 89 MA 02111-1307, USA. */ |
|
Line 130 MA 02111-1307, USA. */ |
|
relaxed. All the places this is used currently call with a<=b though. */ |
relaxed. All the places this is used currently call with a<=b though. */ |
|
|
int |
int |
#if __STDC__ |
|
mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int result_bit1) |
mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int result_bit1) |
#else |
|
mpn_jacobi_base (a, b, result_bit1) |
|
mp_limb_t a; |
|
mp_limb_t b; |
|
int result_bit1; |
|
#endif |
|
{ |
{ |
ASSERT (b & 1); /* b odd */ |
ASSERT (b & 1); /* b odd */ |
ASSERT (b != 1); |
ASSERT (b != 1); |
Line 116 mpn_jacobi_base (a, b, result_bit1) |
|
Line 150 mpn_jacobi_base (a, b, result_bit1) |
|
|
|
do |
do |
{ |
{ |
/* working on (a/b), a,b odd, a>=b */ |
/* working on (a/b), a,b odd, a>=b */ |
ASSERT (a & 1); |
ASSERT (a & 1); |
ASSERT (b & 1); |
ASSERT (b & 1); |
ASSERT (a >= b); |
ASSERT (a >= b); |
|
|
if ((a -= b) == 0) |
if ((a -= b) == 0) |
return 0; |
return 0; |
|
|
PROCESS_TWOS_EVEN; |
PROCESS_TWOS_EVEN; |
if (a == 1) |
if (a == 1) |
goto done; |
goto done; |
} |
} |