summaryrefslogtreecommitdiff
path: root/mpz/kronuz.c
blob: 63972f22c60ad38fb2f0d5a1a5fcdcebf405e518 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* mpz_ui_kronecker -- Kronecker/Jacobi symbol. */

/*
Copyright (C) 1999, 2000 Free Software Foundation, Inc.

This file is part of the GNU MP Library.

The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.

The GNU MP Library 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 Library General Public
License for more details.

You should have received a copy of the GNU Library General Public License
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,
MA 02111-1307, USA.
*/

#include "gmp.h"
#include "gmp-impl.h"
#include "longlong.h"


int
#if __STDC__
mpz_ui_kronecker (unsigned long a, mpz_srcptr b)
#else
mpz_ui_kronecker (a, b)
     unsigned long a;
     mpz_srcptr    b;
#endif
{
  int        b_abs_size;
  mp_srcptr  b_ptr;
  mp_limb_t  b_low;
  int        twos;
  int        result_bit1;

  /* (a/0) */
  b_abs_size = ABSIZ (b);
  if (b_abs_size == 0)
    return JACOBI_U0 (a);

  /* (a/-1)=1 when a>=0, so the sign of b is ignored */
  b_ptr = PTR(b);
  b_low = b_ptr[0];

  /* (0/1)=1; (0/-1)=1; (0/b)=0 for b!=+/-1
     (1/b)=1, for any b */
  if (a <= 1)
    return (a == 1) | ((b_abs_size == 1) & (b_low == 1));

  if (b_low & 1)
    {
      /* (a/1) = 1 for any a */
      if (b_abs_size == 1 && b_low == 1)
        return 1;

      count_trailing_zeros (twos, a);
      a >>= twos;
      if (a == 1)
        return JACOBI_TWOS_U (twos, b_low);  /* powers of (2/b) only */

      /* powers of (2/b); reciprocity to (b/a); (b/a) == (b mod a / a) */
      return mpn_jacobi_base (mpn_mod_1 (b_ptr, b_abs_size, a),
                              a,
                              JACOBI_TWOS_U_BIT1 (twos, b_low)
                              ^ JACOBI_RECIP_UU_BIT1 (b_low, a));
    }

  /* b is even; (a/2)=0 if a is even */
  if ((a & 1) == 0)
    return 0;

  /* Require MP_BITS_PER_LIMB even, so (a/2)^MP_BITS_PER_LIMB = 1, and so we
     don't have to pay attention to how many trailing zero limbs are
     stripped.  */
  ASSERT ((BITS_PER_MP_LIMB & 1) == 0);

  MPN_STRIP_LOW_ZEROS_NOT_ZERO (b_ptr, b_abs_size);
  b_low = b_ptr[0];

  if (b_low & 1)
    /* reciprocity to (b/a); (b/a) == (b mod a / a) */
    return mpn_jacobi_base (mpn_mod_1 (b_ptr, b_abs_size, a),
                            a,
                            JACOBI_RECIP_UU_BIT1 (b_low, a));

  count_trailing_zeros (twos, b_low);

  /* reciprocity to get (b/a) */
  if (twos == BITS_PER_MP_LIMB-1)
    {
      if (b_abs_size == 1)
        {
          /* b==0x800...00, one limb high bit only, so (a/2)^(BPML-1) */
          return JACOBI_TWOS_U (BITS_PER_MP_LIMB-1, a);
        }

      /* b_abs_size > 1 */
      result_bit1 = JACOBI_RECIP_UU_BIT1 (a, b_ptr[1] << 1);
    }
  else
    result_bit1 = JACOBI_RECIP_UU_BIT1 (a, b_low >> twos);

  /* powers of (a/2); reciprocity to (b/a); (b/a) == (b mod a / a) */
  return mpn_jacobi_base (mpn_mod_1_rshift (b_ptr, b_abs_size, twos, a),
                          a,
                          JACOBI_TWOS_U_BIT1 (twos, a) ^ result_bit1);
}