@@ -256,30 +256,51 @@ pub fn binomial(p : ValidPrime, n : i32, k : i32) -> u32 {
256
256
}
257
257
258
258
/// Binomial coefficients mod 4 up to a sign (we always return 0, 1 or 2)
259
- /// This uses the fact that v_2(n choose r) is the number of borrows performed when subtracting r
260
- /// from n
261
- pub fn binomial4 ( n : u32 , k : u32 ) -> u32 {
262
- if ( n - k) & k == 0 {
263
- return 1
259
+ /// This uses the algorithm from https://www.fq.math.ca/Scanned/29-1/davis.pdf
260
+ pub fn binomial4 ( n : u32 , j : u32 ) -> u32 {
261
+ if n < 2 {
262
+ return 1 ;
263
+ }
264
+ if ( n - j) & j == 0 {
265
+ // Answer is odd
266
+ let k = 32 - n. leading_zeros ( ) - 1 ;
267
+ let l = n - ( 1 << k) ;
268
+ if l < ( 1 << ( k - 1 ) ) {
269
+ if j <= l {
270
+ binomial4 ( l, j)
271
+ } else {
272
+ binomial4 ( l, j - ( 1 << k) )
273
+ }
274
+ } else {
275
+ if j < ( 1 << ( k - 1 ) ) {
276
+ binomial4 ( l, j)
277
+ } else if j <= l {
278
+ ( binomial4 ( l, j) + 2 * binomial2 ( l as i32 , ( j - ( 1 << k - 1 ) ) as i32 ) ) % 4
279
+ } else if j <= l + ( 1 << k) {
280
+ ( 2 * binomial2 ( l as i32 , ( j - ( 1 << k - 1 ) ) as i32 ) + binomial4 ( l, j - ( 1 << k) ) ) % 4
281
+ } else {
282
+ binomial4 ( l, j - ( 1 << k) )
283
+ }
284
+ }
264
285
} else {
265
286
// 1 at the first borrow position
266
- let fb = 1 << ( ( n - k ) & k ) . trailing_zeros ( ) ;
287
+ let fb = 1 << ( ( n - j ) & j ) . trailing_zeros ( ) ;
267
288
if n & ( fb << 1 ) == 0 {
268
289
// This borrow requires a further borrow on the left
269
290
return 0 ;
270
- } else if k & ( fb << 1 ) != 0 {
271
- // In n there is a 1 to the left, but there is a 1 in k as well, so we need to borrow
291
+ } else if j & ( fb << 1 ) != 0 {
292
+ // In n there is a 1 to the left, but there is a 1 in j as well, so we need to borrow
272
293
// once more
273
294
return 0 ;
274
- } else {
275
- // Remove the digit where we need to borrow. Check there is no further need to borrow
276
- let k2 = k ^ fb;
277
- if ( n - k2 ) & k2 == 0 {
295
+ } else {
296
+ // Remove the digit where we need to borrow. Checj there is no further need to borrow
297
+ let j2 = j ^ fb;
298
+ if ( n - j2 ) & j2 == 0 {
278
299
return 2 ;
279
300
} else {
280
301
return 0 ;
281
302
}
282
- }
303
+ }
283
304
}
284
305
}
285
306
@@ -290,9 +311,8 @@ pub fn multinomial4(l: &[u32]) -> u32 {
290
311
let sum = l. iter ( ) . sum ( ) ;
291
312
match binomial4 ( sum, l[ 0 ] ) {
292
313
0 => 0 ,
293
- 1 => multinomial4 ( & l[ 1 ..] ) ,
294
314
2 => 2 * multinomial2 ( & l[ 1 ..] ) ,
295
- _ => unreachable ! ( ) ,
315
+ x => ( x * multinomial4 ( & l [ 1 .. ] ) ) % 4 ,
296
316
}
297
317
}
298
318
}
@@ -449,19 +469,13 @@ mod tests {
449
469
}
450
470
451
471
#[ test]
452
- fn test_binomial4 ( ) {
472
+ fn binomial4_cmp ( ) {
453
473
for n in 0 .. 12 {
454
474
for j in 0 ..= ( n + 1 ) / 2 {
455
- let mut ans = match binomial_full ( n, j) % 4 {
456
- 1 | 3 => 1 ,
457
- 2 => 2 ,
458
- _ => 0
459
- } ;
460
- assert_eq ! ( binomial4( n, j) , ans) ;
475
+ assert_eq ! ( binomial4( n, j) , binomial_full( n, j) % 4 ) ;
461
476
}
462
477
}
463
478
}
464
-
465
479
}
466
480
467
481
pub const PRIMES : [ u32 ; NUM_PRIMES ] = [ 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 ] ;
0 commit comments