Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/bernoulli_mod_p.pyx
4091 views
1
r"""
2
Bernoulli numbers modulo p
3
4
AUTHOR:
5
- David Harvey (2006-07-26): initial version
6
- William Stein (2006-07-28): some touch up.
7
- David Harvey (2006-08-06): new, faster algorithm, also using faster NTL interface
8
- David Harvey (2007-08-31): algorithm for a single Bernoulli number mod p
9
- David Harvey (2008-06): added interface to bernmm, removed old code
10
"""
11
12
#*****************************************************************************
13
# Copyright (C) 2006 William Stein <[email protected]>
14
# 2006 David Harvey <[email protected]>
15
#
16
# Distributed under the terms of the GNU General Public License (GPL)
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
cimport sage.rings.fast_arith
21
import sage.rings.fast_arith
22
cdef sage.rings.fast_arith.arith_int arith_int
23
arith_int = sage.rings.fast_arith.arith_int()
24
25
ctypedef long long llong
26
27
import sage.rings.arith
28
29
from sage.libs.ntl import all as ntl
30
from sage.libs.ntl.ntl_ZZ_pX cimport ntl_ZZ_pX
31
import sage.libs.pari.gen
32
from sage.rings.finite_rings.integer_mod_ring import Integers
33
from sage.rings.bernmm import bernmm_bern_modp
34
35
36
37
def verify_bernoulli_mod_p(data):
38
"""
39
Computes checksum for bernoulli numbers.
40
41
It checks the identity
42
$$ \sum_{n=0}^{(p-3)/2} 2^{2n} (2n+1) B_{2n} \equiv -2 \pmod p $$
43
44
(see "Irregular Primes to One Million", Buhler et al)
45
46
INPUT:
47
data -- list, same format as output of bernoulli_mod_p function
48
49
OUTPUT:
50
bool -- True if checksum passed
51
52
EXAMPLES:
53
sage: from sage.rings.bernoulli_mod_p import verify_bernoulli_mod_p
54
sage: verify_bernoulli_mod_p(bernoulli_mod_p(next_prime(3)))
55
True
56
sage: verify_bernoulli_mod_p(bernoulli_mod_p(next_prime(1000)))
57
True
58
sage: verify_bernoulli_mod_p([1, 2, 4, 5, 4])
59
True
60
sage: verify_bernoulli_mod_p([1, 2, 3, 4, 5])
61
False
62
63
This one should test that long longs are working:
64
sage: verify_bernoulli_mod_p(bernoulli_mod_p(next_prime(20000)))
65
True
66
67
AUTHOR: David Harvey
68
"""
69
70
cdef int N, p, i, product, sum, value, element
71
N = len(data)
72
p = N*2 + 1
73
product = 1
74
sum = 0
75
for i from 0 <= i < N:
76
element = data[i]
77
value = <int> (((((<llong> product) * (2*i+1)) % p) * element) % p)
78
sum = (sum + value) % p
79
product = (4 * product) % p
80
81
if (sum + 2) % p == 0:
82
return True
83
else:
84
return False
85
86
87
def bernoulli_mod_p(int p):
88
r"""
89
Returns the bernoulli numbers $B_0, B_2, ... B_{p-3}$ modulo $p$.
90
91
INPUT:
92
p -- integer, a prime
93
94
OUTPUT:
95
list -- Bernoulli numbers modulo $p$ as a list
96
of integers [B(0), B(2), ... B(p-3)].
97
98
ALGORITHM:
99
Described in accompanying latex file.
100
101
PERFORMANCE:
102
Should be complexity $O(p \log p)$.
103
104
EXAMPLES:
105
Check the results against PARI's C-library implementation (that
106
computes exact rationals) for $p = 37$:
107
108
sage: bernoulli_mod_p(37)
109
[1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2]
110
sage: [bernoulli(n) % 37 for n in xrange(0, 36, 2)]
111
[1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2]
112
113
Boundary case:
114
sage: bernoulli_mod_p(3)
115
[1]
116
117
AUTHOR:
118
-- David Harvey (2006-08-06)
119
120
"""
121
122
if p <= 2:
123
raise ValueError, "p (=%s) must be a prime >= 3"%p
124
125
if not sage.libs.pari.gen.pari(p).isprime():
126
raise ValueError, "p (=%s) must be a prime"%p
127
128
cdef int g, gSqr, gInv, gInvSqr, isOdd
129
130
g = sage.rings.arith.primitive_root(p)
131
gInv = arith_int.c_inverse_mod_int(g, p)
132
gSqr = ((<llong> g) * g) % p
133
gInvSqr = ((<llong> gInv) * gInv) % p
134
isOdd = ((p-1)/2) % 2
135
136
# STEP 1: compute the polynomials G(X) and J(X)
137
138
# These hold g^{i-1} and g^{-i} at the beginning of each iteration
139
cdef llong gPower, gPowerInv
140
gPower = gInv
141
gPowerInv = 1
142
143
# "constant" is (g-1)/2 mod p
144
cdef int constant
145
if g % 2:
146
constant = (g-1)/2
147
else:
148
constant = (g+p-1)/2
149
150
# fudge holds g^{i^2}, fudgeInv holds g^{-i^2}
151
cdef int fudge, fudgeInv
152
fudge = fudgeInv = 1
153
154
cdef ntl_ZZ_pX G, J
155
G = ntl.ZZ_pX([], ntl.ZZ(p))
156
J = ntl.ZZ_pX([], ntl.ZZ(p))
157
G.preallocate_space((p-1)/2)
158
J.preallocate_space((p-1)/2)
159
160
cdef int i
161
cdef llong temp, h
162
for i from 0 <= i < (p-1)/2:
163
# compute h = h(g^i)/g^i (h(x) is as in latex notes)
164
temp = g * gPower
165
h = ((p + constant - (temp / p)) * gPowerInv) % p
166
gPower = temp % p
167
gPowerInv = (gPowerInv * gInv) % p
168
169
# store the coefficient g^{i^2} h(g^i)/g^i
170
G.setitem_from_int(i, <int> ((h * fudge) % p))
171
172
# store the coefficient g^{-i^2}
173
J.setitem_from_int(i, fudgeInv)
174
175
# update fudge and fudgeInv
176
fudge = (((fudge * gPower) % p) * ((gPower * g) % p)) % p
177
fudgeInv = (((fudgeInv * gPowerInv) % p) * ((gPowerInv * g) % p)) % p
178
179
J.setitem_from_int(0, 0)
180
181
# STEP 2: multiply the polynomials
182
183
cdef ntl_ZZ_pX product
184
product = G * J
185
186
# STEP 3: assemble the result
187
188
cdef int gSqrPower, value
189
output = [1]
190
gSqrPower = gSqr
191
fudge = g
192
for i from 1 <= i < (p-1)/2:
193
value = product.getitem_as_int(i + (p-1)/2)
194
195
if isOdd:
196
value = (G.getitem_as_int(i) + product.getitem_as_int(i) - value + p) % p
197
else:
198
value = (G.getitem_as_int(i) + product.getitem_as_int(i) + value) % p
199
200
value = (((4 * i * (<llong> fudge)) % p) * (<llong> value)) % p
201
value = ((<llong> value) * (arith_int.c_inverse_mod_int(1 - gSqrPower, p))) % p
202
203
output.append(value)
204
205
gSqrPower = ((<llong> gSqrPower) * g) % p
206
fudge = ((<llong> fudge) * gSqrPower) % p
207
gSqrPower = ((<llong> gSqrPower) * g) % p
208
209
return output
210
211
212
213
def bernoulli_mod_p_single(long p, long k):
214
r"""
215
Returns the bernoulli number $B_k$ mod $p$.
216
217
If $B_k$ is not $p$-integral, an ArithmeticError is raised.
218
219
INPUT:
220
p -- integer, a prime
221
k -- non-negative integer
222
223
OUTPUT:
224
The $k$-th bernoulli number mod $p$.
225
226
EXAMPLES:
227
sage: bernoulli_mod_p_single(1009, 48)
228
628
229
sage: bernoulli(48) % 1009
230
628
231
232
sage: bernoulli_mod_p_single(1, 5)
233
Traceback (most recent call last):
234
...
235
ValueError: p (=1) must be a prime >= 3
236
237
sage: bernoulli_mod_p_single(100, 4)
238
Traceback (most recent call last):
239
...
240
ValueError: p (=100) must be a prime
241
242
sage: bernoulli_mod_p_single(19, 5)
243
0
244
245
sage: bernoulli_mod_p_single(19, 18)
246
Traceback (most recent call last):
247
...
248
ArithmeticError: B_k is not integral at p
249
250
sage: bernoulli_mod_p_single(19, -4)
251
Traceback (most recent call last):
252
...
253
ValueError: k must be non-negative
254
255
Check results against bernoulli_mod_p:
256
257
sage: bernoulli_mod_p(37)
258
[1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2]
259
sage: [bernoulli_mod_p_single(37, n) % 37 for n in xrange(0, 36, 2)]
260
[1, 31, 16, 15, 16, 4, 17, 32, 22, 31, 15, 15, 17, 12, 29, 2, 0, 2]
261
262
sage: bernoulli_mod_p(31)
263
[1, 26, 1, 17, 1, 9, 11, 27, 14, 23, 13, 22, 14, 8, 14]
264
sage: [bernoulli_mod_p_single(31, n) % 31 for n in xrange(0, 30, 2)]
265
[1, 26, 1, 17, 1, 9, 11, 27, 14, 23, 13, 22, 14, 8, 14]
266
267
sage: bernoulli_mod_p(3)
268
[1]
269
sage: [bernoulli_mod_p_single(3, n) % 3 for n in xrange(0, 2, 2)]
270
[1]
271
272
sage: bernoulli_mod_p(5)
273
[1, 1]
274
sage: [bernoulli_mod_p_single(5, n) % 5 for n in xrange(0, 4, 2)]
275
[1, 1]
276
277
sage: bernoulli_mod_p(7)
278
[1, 6, 3]
279
sage: [bernoulli_mod_p_single(7, n) % 7 for n in xrange(0, 6, 2)]
280
[1, 6, 3]
281
282
AUTHOR:
283
-- David Harvey (2007-08-31)
284
-- David Harvey (2008-06): rewrote to use bernmm library
285
286
"""
287
if p <= 2:
288
raise ValueError, "p (=%s) must be a prime >= 3"%p
289
290
if not sage.libs.pari.gen.pari(p).isprime():
291
raise ValueError, "p (=%s) must be a prime"%p
292
293
R = Integers(p)
294
295
cdef long x = bernmm_bern_modp(p, k)
296
if x == -1:
297
raise ArithmeticError, "B_k is not integral at p"
298
return x
299
300
301
# ============ end of file
302
303