ruby-numtheory 0.0.4-x86-linux → 0.0.5-x86-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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-linux
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