ruby-numtheory 0.0.4-x86-mingw32 → 0.0.5-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/ext/numtheory/numtheory.c +150 -32
  2. data/lib/numtheory.so +0 -0
  3. metadata +4 -4
@@ -217,6 +217,10 @@ inline static VALUE SUB(VALUE x, VALUE y) {
217
217
  rb_big_minus(TO_BIGNUM(x), y);
218
218
  }
219
219
 
220
+ #define NEGATE(x) do { if (FIXNUM_P(x)) x = -x; \
221
+ else RBIGNUM_SET_SIGN(x, !RBIGNUM_SIGN(x)); } \
222
+ while(0);
223
+
220
224
  inline static VALUE MUL(VALUE x, VALUE y) {
221
225
  return rb_funcall(x, id_mul, 1, y);
222
226
  }
@@ -243,7 +247,19 @@ inline static VALUE DIVMOD(VALUE x, VALUE y) {
243
247
  inline static VALUE MOD(VALUE x, VALUE y) {
244
248
  return rb_funcall(x, id_mod, 1, y);
245
249
  }
246
-
250
+
251
+ inline static int MOD_4(VALUE x) {
252
+ return FIXNUM_P(x) ? FIX2LONG(x) & 3 :
253
+ RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 3 :
254
+ 4 - RBIGNUM_DIGITS(x)[0] & 3;
255
+ }
256
+
257
+ inline static int MOD_8(VALUE x) {
258
+ return FIXNUM_P(x) ? FIX2LONG(x) & 7 :
259
+ RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 7 :
260
+ 8 - RBIGNUM_DIGITS(x)[0] & 7;
261
+ }
262
+
247
263
  inline static int EQL(VALUE x, VALUE y) {
248
264
  return (FIXNUM_P(x) && FIXNUM_P(y)) ?
249
265
  x == y :
@@ -345,6 +361,8 @@ numtheory_powermod(int argc, VALUE *argv)
345
361
  return result;
346
362
  }
347
363
 
364
+ static VALUE int_powermod_sliding_window(VALUE,VALUE,VALUE);
365
+
348
366
  /*
349
367
  * call-seq:
350
368
  * integer.powermod(power, modulo) -> integer
@@ -356,7 +374,6 @@ numtheory_powermod(int argc, VALUE *argv)
356
374
  */
357
375
  static VALUE
358
376
  numtheory_int_powermod(VALUE b, VALUE p, VALUE m){
359
- VALUE result = one;
360
377
  if (!INTEGER_P(p))
361
378
  {
362
379
  rb_raise(rb_eArgError, "power must be integer");
@@ -365,16 +382,32 @@ numtheory_int_powermod(VALUE b, VALUE p, VALUE m){
365
382
  {
366
383
  rb_raise(rb_eTypeError, "modulo must be integer");
367
384
  }
385
+ if (ZERO_P(p))
386
+ {
387
+ return one;
388
+ }
368
389
  if (NEGATIVE_P(p))
369
390
  {
370
391
  b = numtheory_modular_inverse(b, m);
371
392
  p = ABS(p);
393
+ }
394
+ else
395
+ {
396
+ b = MOD(b, m);
397
+ }
398
+ if (FIXNUM_P(p) || RBIGNUM_LEN(p) < 4)
399
+ {
400
+ VALUE result = one;
401
+ FOR_BITS(p, result = MUL(result, result),
402
+ {},
403
+ result = MUL(result, b),
404
+ result = MOD(result, m));
405
+ return result;
406
+ }
407
+ else
408
+ {
409
+ return int_powermod_sliding_window(b, p, m);
372
410
  }
373
- FOR_BITS(p, result = MUL(result, result),
374
- {},
375
- result = MUL(result, b),
376
- result = MOD(result, m));
377
- return result;
378
411
  }
379
412
 
380
413
  static int tail_zeros(VALUE n)
@@ -1378,48 +1411,52 @@ numtheory_jacobi(VALUE a, VALUE n)
1378
1411
  {
1379
1412
  rb_raise(rb_eArgError, "n must be odd positive");
1380
1413
  }
1381
- int t = 1;
1414
+ int t = 1, z;
1382
1415
  VALUE tmp;
1416
+
1417
+ a = MOD(a, n);
1418
+ if (MORE(a, HALF(n))) {
1419
+ a = SUB(a, n);
1420
+ }
1421
+
1383
1422
  while (!ZERO_P(a))
1384
1423
  {
1385
- a = MOD(a, n);
1386
- if (MORE(a, HALF(n)))
1424
+ if (FIXNUM_P(n) && FIXNUM_P(a))
1387
1425
  {
1388
- a = SUB(a, n);
1389
- }
1390
- if (FIXNUM_P(n))
1391
- {
1392
- return INT2FIX(ull_jacobi(FIX2LONG(a), FIX2LONG(n)));
1426
+ return INT2FIX(t * ull_jacobi(FIX2LONG(a), FIX2LONG(n)));
1393
1427
  }
1394
1428
  if (RBIGNUM_LEN(n) <= 2) // unsigned long long is used
1395
1429
  {
1396
- return INT2FIX(ull_jacobi(FIXNUM_P(a) ? FIX2LONG(a) : rb_big2ll(a),
1397
- rb_big2ull(n)));
1430
+ return INT2FIX(t * ull_jacobi(FIXNUM_P(a) ? FIX2LONG(a) : rb_big2ll(a),
1431
+ rb_big2ull(n)));
1398
1432
  }
1399
1433
  if (NEGATIVE_P(a))
1400
1434
  {
1401
- a = SUB(zero, a);
1402
- if (MOD(n, four) == three)
1435
+ NEGATE(a);
1436
+ if (MOD_4(n) == 3)
1403
1437
  t = -t;
1404
1438
  }
1405
- switch (FIX2LONG(MOD(n, eight)))
1439
+ z = tail_zeros(a);
1440
+ a = RIGHT_SHIFT(a, z);
1441
+ if (z & 1)
1406
1442
  {
1407
- case 1:
1408
- case 7:
1409
- while (EVEN_P(a))
1410
- a = HALF(a);
1411
- break;
1412
- case 3:
1413
- case 5:
1414
- while (EVEN_P(a))
1415
- a = HALF(a), t = -t;
1416
- break;
1443
+ switch (MOD_8(n))
1444
+ {
1445
+ case 3:
1446
+ case 5:
1447
+ t = -t;
1448
+ break;
1449
+ }
1417
1450
  }
1418
1451
  tmp = a;
1419
1452
  a = n;
1420
- n = tmp;
1421
- if (MOD(a, four) == three && MOD(n, four) == three)
1453
+ n = tmp; /* n > 0 */
1454
+ if (MOD_4(a) == 3 && MOD_4(n) == 3)
1422
1455
  t = -t;
1456
+ a = MOD(a, n);
1457
+ if (MORE(a, HALF(n))) {
1458
+ a = SUB(a, n);
1459
+ }
1423
1460
  }
1424
1461
  if (n == one)
1425
1462
  {
@@ -1724,3 +1761,84 @@ numtheory_bpsw_pseudoprime_p(VALUE n)
1724
1761
 
1725
1762
  return lucas_pseudoprime_p(num, one, RIGHT_SHIFT(SUB(one, INT2FIX(d)), 2));
1726
1763
  }
1764
+
1765
+ static VALUE
1766
+ int_powermod_sliding_window(VALUE b, VALUE p, VALUE m){
1767
+ VALUE result = one;
1768
+ /* used when p is bignum only */
1769
+ enum { squaring, collecting } state;
1770
+
1771
+ state = collecting;
1772
+ int len, k;
1773
+ int zeros = 0;
1774
+ int pow = 0;
1775
+
1776
+ /* adjusting window size */
1777
+ len = RBIGNUM_LEN(p);
1778
+ if (len < 8) k = 4;
1779
+ else if (len < 20) k = 5;
1780
+ else if (len < 48) k = 6;
1781
+ else k = 7;
1782
+
1783
+ len = 0;
1784
+
1785
+ VALUE b_squared = MOD(MUL(b, b), m);
1786
+ VALUE *powers = ALLOCA_N(VALUE, 1<<(k-1));
1787
+ powers[0] = b;
1788
+ int i;
1789
+ /* precomputation of odd powers;
1790
+ powers[n] = (b ** (2n + 1)) % m */
1791
+ for (i = 1; i < (1<<(k-1)); ++i)
1792
+ powers[i] = MOD(MUL(powers[i-1], b_squared), m);
1793
+
1794
+ FOR_BITS(p, {},
1795
+ { /* if the bit is zero */
1796
+ if (state == collecting) {
1797
+ ++ len;
1798
+ ++ zeros;
1799
+ pow <<= 1;
1800
+ if (len == k) {
1801
+ pow >>= zeros;
1802
+
1803
+ for (i = len; i > zeros; i--)
1804
+ result = MOD(MUL(result, result), m);
1805
+ result = MOD(MUL(result, powers[pow>>1]), m);
1806
+ while (zeros--)
1807
+ result = MOD(MUL(result, result), m);
1808
+
1809
+ state = squaring; pow = len = zeros = 0;
1810
+ }
1811
+ } else {
1812
+ result = MOD(MUL(result, result), m);
1813
+ }
1814
+ },
1815
+ { /* the bit is one */
1816
+ if (state == collecting) {
1817
+ ++ len;
1818
+ zeros = 0;
1819
+ pow = (pow << 1) + 1;
1820
+ if (len == k) {
1821
+ while (len--)
1822
+ result = MOD(MUL(result, result), m);
1823
+ result = MOD(MUL(result, powers[pow>>1]), m);
1824
+ state = squaring;
1825
+ pow = len = 0;
1826
+ }
1827
+ } else {
1828
+ state = collecting;
1829
+ pow = 1;
1830
+ len = 1;
1831
+ zeros = 0;
1832
+ }
1833
+ }, {});
1834
+ if (len > 0) {
1835
+ pow >>= zeros;
1836
+
1837
+ for (i = len; i > zeros; i--)
1838
+ result = MOD(MUL(result, result), m);
1839
+ result = MOD(MUL(result, powers[pow>>1]), m);
1840
+ while (zeros--)
1841
+ result = MOD(MUL(result, result), m);
1842
+ }
1843
+ return result;
1844
+ }
data/lib/numtheory.so CHANGED
Binary file
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 4
9
- version: 0.0.4
8
+ - 5
9
+ version: 0.0.5
10
10
  platform: x86-mingw32
11
11
  authors:
12
12
  - lomereiter
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-05-16 00:00:00 +04:00
17
+ date: 2011-05-27 00:00:00 +04:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
21
- description: fast implementations of common number-theoretical algorithms
21
+ description: " The library is written as C extension and aims to provide\n common number-theoretical functions such as powermod, jacobi symbol,\n various multiplicative ones, etc.\n"
22
22
  email: lomereiter@gmail.com
23
23
  executables: []
24
24