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