ruby-numtheory 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  The library is written as C extension and aims to provide fast implementations of common number-theoretical algorithms.
4
4
 
5
+ [![Build Status](https://secure.travis-ci.org/lomereiter/ruby-numtheory.png)](http://travis-ci.org/lomereiter/ruby-numtheory)
6
+
5
7
  ## Currently implemented
6
8
 
7
9
  * powermod (uses sliding window exponentiation)
data/Rakefile CHANGED
@@ -11,24 +11,24 @@ rescue Bundler::BundlerError => e
11
11
  end
12
12
  require 'rake'
13
13
 
14
- spec = Gem::Specification.load('ruby-numtheory.gemspec')
15
-
16
14
  require 'rspec/core'
17
15
  require 'rspec/core/rake_task'
18
16
  RSpec::Core::RakeTask.new(:spec) do |spec|
19
17
  spec.pattern = FileList["spec/**/*_spec.rb"]
20
18
  end
21
19
 
22
- task :test => :spec
23
- task :default => :test
24
-
20
+ spec = Gem::Specification.load('ruby-numtheory.gemspec')
21
+
25
22
  require 'rubygems/package_task'
26
23
  Gem::PackageTask.new(spec) do |pkg|
27
24
  end
28
25
 
29
- task :build => :gem
30
-
31
26
  require 'rake/extensiontask'
32
27
  Rake::ExtensionTask.new('numtheory', spec) do |ext|
33
28
  ext.cross_compile = true
34
29
  end
30
+
31
+ task :spec => :compile
32
+ task :test => :spec
33
+ task :default => :test
34
+ task :build => :gem
@@ -1,3 +1,3 @@
1
1
  require 'mkmf'
2
- $CFLAGS = "-g -O3 -funroll-all-loops -fPIC -pedantic -std=c99"
2
+ $CFLAGS = "-g -O3 -funroll-all-loops -fPIC -pedantic -std=c99 -Wall -Wno-unused-but-set-variable"
3
3
  create_makefile 'numtheory'
@@ -2,10 +2,16 @@
2
2
 
3
3
  #include "primes.h"
4
4
  #include "queue.h"
5
+ #if RUBY_VERSION_MINOR != 8
5
6
  #include "reduce.h"
6
- #include "numtheory_macros.c"
7
+ #endif
8
+ #include "numtheory_macros.h"
7
9
  #include "constants.h"
8
10
 
11
+ #ifdef DEBUG
12
+ #include <stdio.h>
13
+ #endif
14
+
9
15
  static VALUE mNumTheory;
10
16
  static ID primality_tests_ID;
11
17
 
@@ -45,6 +51,10 @@ Init_numtheory()
45
51
  id_lcm = rb_intern("lcm");
46
52
  id_pow = rb_intern("**");
47
53
  id_mul = rb_intern("*");
54
+ #if RUBY_VERSION_MINOR == 8
55
+ id_cmp = rb_intern("<=>");
56
+ id_equal = rb_intern("==");
57
+ #endif
48
58
 
49
59
  primality_tests_ID = rb_intern("PrimalityTests");
50
60
  /* PrimalityTests: the number of rounds in Miller-Rabin test for primality. */
@@ -122,7 +132,7 @@ Init_numtheory()
122
132
  *
123
133
  * NumTheory.precompute_primes_upto(20000000)
124
134
  */
125
- static VALUE
135
+ VALUE
126
136
  numtheory_precompute_primes_upto(VALUE obj, VALUE n)
127
137
  {
128
138
  if (FIXNUM_P(n))
@@ -166,7 +176,7 @@ numtheory_precompute_primes_upto(VALUE obj, VALUE n)
166
176
  * Matrix.identity(2))
167
177
  * #=> Matrix[[10946, 6765], [6765, 4181]]
168
178
  */
169
- static VALUE
179
+ VALUE
170
180
  numtheory_powermod(int argc, VALUE *argv)
171
181
  {
172
182
  VALUE base, pow, modulo, one;
@@ -175,7 +185,7 @@ numtheory_powermod(int argc, VALUE *argv)
175
185
  ID id_mul = rb_intern("*");
176
186
  ID id_mod = rb_intern("%");
177
187
 
178
- VALUE result = NIL_P(one) ? rb_uint2big(1) : one;
188
+ VALUE result = NIL_P(one) ? INT2BIG(1) : one;
179
189
  FOR_BITS(pow, result = rb_funcall(result, id_mul, 1, result),
180
190
  {},
181
191
  result = rb_funcall(result, id_mul, 1, base),
@@ -187,7 +197,9 @@ numtheory_powermod(int argc, VALUE *argv)
187
197
  }
188
198
 
189
199
  static VALUE int_powermod_sliding_window(VALUE,VALUE,VALUE);
200
+ #if RUBY_VERSION_MINOR != 8
190
201
  static VALUE int_powermod_sliding_window_br(VALUE,VALUE,VALUE);
202
+ #endif
191
203
 
192
204
  /*
193
205
  * call-seq:
@@ -198,7 +210,7 @@ static VALUE int_powermod_sliding_window_br(VALUE,VALUE,VALUE);
198
210
  *
199
211
  * 172.powermod(238, 239) #=> 1
200
212
  */
201
- static VALUE
213
+ VALUE
202
214
  numtheory_int_powermod(VALUE b, VALUE p, VALUE m){
203
215
  if (!INTEGER_P(p))
204
216
  {
@@ -233,8 +245,10 @@ numtheory_int_powermod(VALUE b, VALUE p, VALUE m){
233
245
  if (!FIXNUM_P(m) && RBIGNUM_LEN(m) >= BARRETT_REDUCE_THRESHOLD)
234
246
  use_barrett = 1;
235
247
 
248
+ #if RUBY_VERSION_MINOR != 8
236
249
  if (use_barrett)
237
250
  return int_powermod_sliding_window_br(b, p, m);
251
+ #endif
238
252
 
239
253
  if (use_sliding_window)
240
254
  return int_powermod_sliding_window(b, p, m);
@@ -251,8 +265,8 @@ static int tail_zeros(VALUE n)
251
265
  {
252
266
  if (FIXNUM_P(n))
253
267
  {
254
- int t = FIX2LONG(n);
255
- int s = 0;
268
+ long t = FIX2LONG(n);
269
+ long s = 0;
256
270
  while (!(t & 1))
257
271
  t >>= 1, ++s;
258
272
  return s;
@@ -261,8 +275,9 @@ static int tail_zeros(VALUE n)
261
275
  {
262
276
  BDIGIT* digit = RBIGNUM_DIGITS(n);
263
277
  unsigned int L = RBIGNUM_LEN(n);
264
- unsigned int i, j, s, z;
265
- const unsigned long MAX = 1 << (SIZEOF_BDIGITS * 8 - 1);
278
+ unsigned int i, s, z;
279
+ unsigned LONG_LONG j;
280
+ const unsigned LONG_LONG MAX = 1ULL << (SIZEOF_BDIGITS * 8 - 1);
266
281
  for (i = s = 0, z = 1; i < L; ++i, ++digit)
267
282
  {
268
283
  for (j = 1; j <= MAX; j <<= 1)
@@ -289,7 +304,7 @@ static int tail_zeros(VALUE n)
289
304
  * accordingly to Miller-Rabin test with <i>NumTheory::PrimalityTests</i>
290
305
  * rounds. Otherwise returns <code>false</code>.
291
306
  */
292
- static VALUE
307
+ VALUE
293
308
  numtheory_miller_rabin_pseudoprime_p(VALUE n)
294
309
  {
295
310
  long PRIMALITY_TESTS = FIX2LONG(rb_const_get(mNumTheory, primality_tests_ID));
@@ -329,7 +344,12 @@ numtheory_miller_rabin_pseudoprime_p(VALUE n)
329
344
  for (i = 0; i < PRIMALITY_TESTS; ++i)
330
345
  {
331
346
 
332
- VALUE a = rb_funcall(rb_cRandom,
347
+ VALUE a = rb_funcall(
348
+ #if RUBY_VERSION_MINOR == 8
349
+ rb_mKernel,
350
+ #else
351
+ rb_cRandom,
352
+ #endif
333
353
  id_rand,
334
354
  1,
335
355
  num_minus_four);
@@ -362,12 +382,12 @@ numtheory_miller_rabin_pseudoprime_p(VALUE n)
362
382
  }
363
383
 
364
384
  inline static int
365
- prime_p(unsigned long t)
385
+ prime_p(unsigned LONG_LONG t)
366
386
  {
367
387
  return (t & 1) ? t == 3 ? 1 :
368
388
  ((t % 6 == 1) || (t % 6 == 5)) ?
369
389
  t < PRIMES_UPPER_LIMIT ?
370
- is_set(numtheory_is_prime, t) ? 1 : 0 :
390
+ is_set(numtheory_is_prime, (unsigned long)t) ? 1 : 0 :
371
391
  numtheory_bpsw_pseudoprime_p(ULL2NUM(t)) :
372
392
  0
373
393
  : t == 2 ? 1 : 0;
@@ -382,16 +402,22 @@ prime_p(unsigned long t)
382
402
  *
383
403
  * 29.prime? #=> true
384
404
  */
385
- static VALUE
405
+ VALUE
386
406
  numtheory_prime_p(VALUE n)
387
407
  {
388
408
  unsigned long t;
389
409
  if (FIXNUM_P(n) && (t = abs(FIX2LONG(n)), t < PRIMES_UPPER_LIMIT))
390
410
  {
411
+ #ifdef DEBUG
412
+ fprintf(stderr, "[prime_p] looking up in the precomputed table...\n");
413
+ #endif
391
414
  return prime_p(t) ? Qtrue : Qfalse;
392
415
  }
393
416
  else
394
417
  {
418
+ #ifdef DEBUG
419
+ fprintf(stderr, "[prime_p] calling BPSW primality test...\n");
420
+ #endif
395
421
  return numtheory_bpsw_pseudoprime_p(n);
396
422
  }
397
423
  }
@@ -404,7 +430,7 @@ numtheory_prime_p(VALUE n)
404
430
  *
405
431
  * (10**28).nextprime #=> 10000000000000000000000000331
406
432
  */
407
- static VALUE
433
+ VALUE
408
434
  numtheory_nextprime(VALUE n)
409
435
  {
410
436
  VALUE p = n;
@@ -437,7 +463,7 @@ nth_prime(long n)
437
463
  * NumTheory.prime 1 #=> 2
438
464
  * NumTheory.prime 1000 #=> 7919
439
465
  */
440
- static VALUE
466
+ VALUE
441
467
  numtheory_prime(VALUE obj, VALUE i)
442
468
  {
443
469
  long t;
@@ -493,7 +519,7 @@ primepi(unsigned long t)
493
519
  * NumTheory.primepi 10 #=> 4
494
520
  * NumTheory.primepi -10 #=> 0
495
521
  */
496
- static VALUE
522
+ VALUE
497
523
  numtheory_primepi(VALUE obj, VALUE n)
498
524
  {
499
525
  if (NEGATIVE_P(n))
@@ -520,7 +546,7 @@ numtheory_primepi(VALUE obj, VALUE n)
520
546
  * NumTheory.fibonacci 10 #=> 55
521
547
  * NumTheory.fibonacci 10**30, 1234567890 #=> 862134135
522
548
  */
523
- static VALUE
549
+ VALUE
524
550
  numtheory_fibonacci(int argc, VALUE* argv)
525
551
  {
526
552
  VALUE n, modulo;
@@ -540,13 +566,13 @@ numtheory_fibonacci(int argc, VALUE* argv)
540
566
  rb_raise(rb_eTypeError, "modulo must be integer");
541
567
  }
542
568
 
543
- VALUE a, b, c, old_a, old_b, old_c, old_b_sq;
569
+ VALUE a, b, c, old_a, old_b_sq, old_c;
544
570
  a = c = one;
545
571
  b = zero;
546
572
 
547
573
  n = SUB(n, one);
548
574
 
549
- FOR_BITS(n, { old_a = a; old_b = b; old_c = c;
575
+ FOR_BITS(n, { old_a = a; old_c = c;
550
576
  old_b_sq = MUL(b, b);
551
577
 
552
578
  a = ADD(MUL(a, a), old_b_sq);
@@ -579,7 +605,7 @@ numtheory_fibonacci(int argc, VALUE* argv)
579
605
  * NumTheory.sigma 1234567890, 0 #=> 48
580
606
  * NumTheory.sigma 1234567890, 1 #=> 3211610688
581
607
  */
582
- static VALUE
608
+ VALUE
583
609
  numtheory_sigma(int argc, VALUE* argv)
584
610
  {
585
611
  VALUE n, pow;
@@ -632,7 +658,7 @@ numtheory_sigma(int argc, VALUE* argv)
632
658
  *
633
659
  * NumTheory.eulerphi(1234567890) #=> 329040288
634
660
  */
635
- static VALUE
661
+ VALUE
636
662
  numtheory_eulerphi(VALUE obj, VALUE n)
637
663
  {
638
664
  if (!INTEGER_P(n))
@@ -665,7 +691,7 @@ numtheory_eulerphi(VALUE obj, VALUE n)
665
691
  * (-987654321).prime_division
666
692
  * #=> [[-1, 1], [3, 2], [17, 2], [379721, 1]]
667
693
  */
668
- static VALUE
694
+ VALUE
669
695
  numtheory_prime_division(VALUE n)
670
696
  {
671
697
  VALUE pd[2];
@@ -701,7 +727,7 @@ numtheory_prime_division(VALUE n)
701
727
  * NumTheory.moebius(4) #=> 0
702
728
  * NumTheory.moebius(35) #=> 1
703
729
  */
704
- static VALUE
730
+ VALUE
705
731
  numtheory_moebius(VALUE obj, VALUE n)
706
732
  {
707
733
  if (!INTEGER_P(n))
@@ -796,10 +822,10 @@ primorial(unsigned long min, unsigned long max)
796
822
  *
797
823
  * NumTheory.product([1,2,3,4,5,6]) #=> 720
798
824
  */
799
- static VALUE
825
+ VALUE
800
826
  numtheory_product(VALUE obj, VALUE arr)
801
827
  {
802
- if (!RB_TYPE_P(arr, T_ARRAY))
828
+ if (TYPE(arr) != T_ARRAY)
803
829
  {
804
830
  rb_raise(rb_eTypeError, "the argument must be an array");
805
831
  }
@@ -815,7 +841,7 @@ numtheory_product(VALUE obj, VALUE arr)
815
841
  *
816
842
  * 2.primes_upto(17).to_a #=> [2, 3, 5, 7, 11, 13, 17]
817
843
  */
818
- static VALUE
844
+ VALUE
819
845
  numtheory_primes_upto(VALUE min, VALUE _max)
820
846
  {
821
847
  VALUE max = _max;
@@ -924,7 +950,7 @@ rec_factorial(long n)
924
950
  *
925
951
  * 50.factorial.to_s(31) #=> "283sp352ltrc9csg1398f0dt7dg067g15ikr4b6spf70"
926
952
  */
927
- static VALUE
953
+ VALUE
928
954
  numtheory_factorial_primeswing(VALUE n)
929
955
  {
930
956
  long t;
@@ -951,7 +977,7 @@ numtheory_factorial_primeswing(VALUE n)
951
977
  q >>= 1;
952
978
  shift += q;
953
979
  }
954
- return rb_big_lshift(rec_factorial(t), LONG2NUM(shift));
980
+ return rb_big_lshift(TO_BIGNUM(rec_factorial(t)), LONG2NUM(shift));
955
981
  }
956
982
 
957
983
  struct Egcd {
@@ -988,7 +1014,7 @@ extended_gcd(VALUE x, VALUE y)
988
1014
  * 0.extended_gcd(0) #=> [0, [0, 0]]
989
1015
  * 239.extended_gcd(932) #=> [1, [39, -10]]
990
1016
  */
991
- static VALUE
1017
+ VALUE
992
1018
  numtheory_extended_gcd(VALUE x, VALUE y)
993
1019
  {
994
1020
  if (!INTEGER_P(y))
@@ -1021,7 +1047,7 @@ numtheory_extended_gcd(VALUE x, VALUE y)
1021
1047
  *
1022
1048
  * 1234.inverse(12345) #=> 9874
1023
1049
  */
1024
- static VALUE
1050
+ VALUE
1025
1051
  numtheory_modular_inverse(VALUE x, VALUE y)
1026
1052
  {
1027
1053
  struct Egcd egcd = extended_gcd(x, y);
@@ -1046,7 +1072,7 @@ numtheory_modular_inverse(VALUE x, VALUE y)
1046
1072
  *
1047
1073
  * 20.znorder(11) => 5
1048
1074
  */
1049
- static VALUE
1075
+ VALUE
1050
1076
  numtheory_multiplicative_order(VALUE a, VALUE m)
1051
1077
  {
1052
1078
  if (rb_funcall(a, id_gcd, 1, m) != one)
@@ -1095,7 +1121,7 @@ static inline VALUE* triple_new(VALUE v1, VALUE v2, VALUE v3)
1095
1121
  * Yields primitive pythagorean triples with perimeter less
1096
1122
  * or equal to <i>max_perimeter</i>.
1097
1123
  */
1098
- static VALUE
1124
+ VALUE
1099
1125
  numtheory_pythagorean_triples(VALUE obj, VALUE max_l)
1100
1126
  {
1101
1127
  RETURN_ENUMERATOR(obj, 1, &max_l);
@@ -1119,7 +1145,11 @@ numtheory_pythagorean_triples(VALUE obj, VALUE max_l)
1119
1145
  }
1120
1146
 
1121
1147
  a = triple[0]; b = triple[1]; c = triple[2];
1148
+ #if RUBY_VERSION_MINOR == 8
1149
+ rb_yield_values(3, triple[0], triple[1], triple[2]);
1150
+ #else
1122
1151
  rb_yield_values2(3, triple);
1152
+ #endif
1123
1153
 
1124
1154
  // uses ternary pythagorean tree
1125
1155
  a2 = DOUBLED(a);
@@ -1152,7 +1182,7 @@ numtheory_pythagorean_triples(VALUE obj, VALUE max_l)
1152
1182
  *
1153
1183
  * Returns the number of set bits.
1154
1184
  */
1155
- static VALUE
1185
+ VALUE
1156
1186
  numtheory_popcount(VALUE n)
1157
1187
  {
1158
1188
  if (NEGATIVE_P(n))
@@ -1165,15 +1195,23 @@ numtheory_popcount(VALUE n)
1165
1195
  }
1166
1196
 
1167
1197
  int
1168
- int_bitlength(unsigned int v)
1198
+ long_bitlength(unsigned long v)
1169
1199
  {
1170
- // taken from http://graphics.stanford.edu/~seander/bithacks.html
1171
- const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
1172
- const unsigned int S[] = {1, 2, 4, 8, 16};
1173
- int i;
1200
+ /* taken from http://graphics.stanford.edu/~seander/bithacks.html */
1174
1201
 
1175
- register unsigned int r = 0;
1202
+ #if SIZEOF_LONG == 8
1203
+ const unsigned long b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000ULL};
1204
+ const unsigned long S[] = {1, 2, 4, 8, 16, 32};
1205
+ int i;
1206
+ register unsigned long r = 0;
1207
+ for (i = 5; i >= 0; --i)
1208
+ #else
1209
+ const unsigned long b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000 };
1210
+ const unsigned long S[] = {1, 2, 4, 8, 16};
1211
+ int i;
1212
+ register unsigned long r = 0;
1176
1213
  for (i = 4; i >= 0; --i)
1214
+ #endif
1177
1215
  {
1178
1216
  if (v & b[i])
1179
1217
  {
@@ -1191,32 +1229,32 @@ int_bitlength(unsigned int v)
1191
1229
  * Returns the length in bits. Defined for positive integers only.
1192
1230
  * 0 is assumed to have length 1.
1193
1231
  */
1194
- static VALUE
1232
+ VALUE
1195
1233
  numtheory_bitlength(VALUE n)
1196
1234
  {
1197
1235
  if (NEGATIVE_P(n))
1198
1236
  {
1199
1237
  rb_raise(rb_eArgError, "n must be positive");
1200
1238
  }
1201
- long bit_len, half_k;
1239
+ long bit_len;
1202
1240
  if (FIXNUM_P(n))
1203
1241
  {
1204
- return INT2FIX(int_bitlength(FIX2LONG(n)));
1242
+ return INT2FIX(long_bitlength(FIX2LONG(n)));
1205
1243
  }
1206
1244
  else
1207
1245
  {
1208
1246
  long len = RBIGNUM_LEN(n);
1209
1247
  bit_len = (len - 1) * SIZEOF_BDIGITS * 8;
1210
- return INT2FIX(bit_len + int_bitlength(RBIGNUM_DIGITS(n)[len - 1]));
1248
+ return INT2FIX(bit_len + long_bitlength(RBIGNUM_DIGITS(n)[len - 1]));
1211
1249
  }
1212
1250
  }
1213
1251
 
1214
1252
  static int
1215
- ull_jacobi(long long a, unsigned long long n)
1253
+ ull_jacobi(LONG_LONG a, unsigned LONG_LONG n)
1216
1254
  {
1217
1255
  /* it's assumed that n is odd and > 0 */
1218
1256
  int t = 1;
1219
- long long tmp;
1257
+ LONG_LONG tmp;
1220
1258
  while (a) {
1221
1259
  if (a < 0) {
1222
1260
  a = -a; if ((n & 3) == 3) t = -t;
@@ -1230,7 +1268,7 @@ ull_jacobi(long long a, unsigned long long n)
1230
1268
  tmp = a; a = n; n = tmp;
1231
1269
  if ((a & 3) == 3 && (n & 3) == 3) t = -t;
1232
1270
  a %= n;
1233
- if (a > (long long)(n >> 1)) a -= n;
1271
+ if (a > (LONG_LONG)(n >> 1)) a -= n;
1234
1272
  }
1235
1273
  return n == 1 ? t : 0;
1236
1274
  }
@@ -1241,7 +1279,7 @@ ull_jacobi(long long a, unsigned long long n)
1241
1279
  *
1242
1280
  * Returns jacobi symbol (a|n) where n must be odd positive
1243
1281
  */
1244
- static VALUE
1282
+ VALUE
1245
1283
  numtheory_jacobi(VALUE a, VALUE n)
1246
1284
  {
1247
1285
  if (EVEN_P(n) || NEGATIVE_P(n))
@@ -1262,7 +1300,7 @@ numtheory_jacobi(VALUE a, VALUE n)
1262
1300
  {
1263
1301
  return INT2FIX(t * ull_jacobi(FIX2LONG(a), FIX2LONG(n)));
1264
1302
  }
1265
- if (RBIGNUM_LEN(n) <= 2) // unsigned long long is used
1303
+ if (RBIGNUM_LEN(n) <= 2) // unsigned LONG_LONG is used
1266
1304
  {
1267
1305
  return INT2FIX(t * ull_jacobi(FIXNUM_P(a) ? FIX2LONG(a) : rb_big2ll(a),
1268
1306
  rb_big2ull(n)));
@@ -1312,7 +1350,7 @@ numtheory_jacobi(VALUE a, VALUE n)
1312
1350
  * If (a|p) = 1 returns the square root of a in Z/pZ
1313
1351
  * from the interval [0, p/2]. Otherwise returns +nil+.
1314
1352
  */
1315
- static VALUE
1353
+ VALUE
1316
1354
  numtheory_sqrtmod(VALUE a, VALUE p)
1317
1355
  {
1318
1356
  if (!INTEGER_P(p))
@@ -1401,7 +1439,7 @@ numtheory_sqrtmod(VALUE a, VALUE p)
1401
1439
  *
1402
1440
  * Returns the square root integer part.
1403
1441
  */
1404
- static VALUE
1442
+ VALUE
1405
1443
  numtheory_isqrt(VALUE n)
1406
1444
  {
1407
1445
  if (NEGATIVE_P(n))
@@ -1438,7 +1476,7 @@ static int MOD_255(VALUE n)
1438
1476
  {
1439
1477
  return FIX2LONG(n) % 255;
1440
1478
  }
1441
- unsigned long long m = 0;
1479
+ unsigned LONG_LONG m = 0;
1442
1480
  BDIGIT* digit = RBIGNUM_DIGITS(n);
1443
1481
  int i;
1444
1482
  for (i = 0; i < RBIGNUM_LEN(n); ++i, ++digit)
@@ -1457,7 +1495,7 @@ static int MOD_255(VALUE n)
1457
1495
  *
1458
1496
  * Checks whether the integer is a perfect square or not.
1459
1497
  */
1460
- static VALUE
1498
+ VALUE
1461
1499
  numtheory_perfect_square_p(VALUE n)
1462
1500
  {
1463
1501
  if (NEGATIVE_P(n))
@@ -1530,19 +1568,32 @@ static VALUE power_of_2_mod(VALUE p, VALUE m){
1530
1568
 
1531
1569
  static VALUE miller_rabin_base2_pseudoprime_p(VALUE n)
1532
1570
  {
1533
- // for internal use only
1571
+ /* for internal use only */
1572
+ #ifdef DEBUG
1573
+ fprintf(stderr, "[miller-rabin base 2] start test for %s...\n", TO_CSTRING(n));
1574
+ #endif
1534
1575
  VALUE num = rb_big_clone(TO_BIGNUM(n));
1535
1576
  VALUE num_minus_one = SUB(num, one);
1536
1577
  VALUE d = rb_big_clone(TO_BIGNUM(num_minus_one));
1537
1578
 
1538
1579
  int s = tail_zeros(d);
1580
+ #ifdef DEBUG
1581
+ fprintf(stderr, "[miller-rabin base 2] p-1 = %s...\n", TO_CSTRING(d));
1582
+ fprintf(stderr, "[miller-rabin base 2] tail zeros: %d\n", s);
1583
+ #endif
1539
1584
  d = RIGHT_SHIFT(d, s);
1540
1585
 
1541
1586
  VALUE x = power_of_2_mod(d, num);
1587
+ #ifdef DEBUG
1588
+ fprintf(stderr, "[miller-rabin base 2] 2**d = %s modulo %s\n", TO_CSTRING(x), TO_CSTRING(num));
1589
+ #endif
1542
1590
  if (EQL(x, one) || EQL(x, num_minus_one)) return Qtrue;
1543
1591
 
1544
1592
  while (s--) {
1545
1593
  x = MOD(MUL(x, x), num);
1594
+ #ifdef DEBUG
1595
+ fprintf(stderr, "[miller-rabin base 2] x = %s modulo %s\n", TO_CSTRING(x), TO_CSTRING(num));
1596
+ #endif
1546
1597
  if (EQL(x, one)) return Qfalse;
1547
1598
  if (EQL(x, num_minus_one)) break;
1548
1599
  }
@@ -1558,7 +1609,7 @@ static VALUE miller_rabin_base2_pseudoprime_p(VALUE n)
1558
1609
  *
1559
1610
  * Standard BPSW primality test.
1560
1611
  */
1561
- static VALUE
1612
+ VALUE
1562
1613
  numtheory_bpsw_pseudoprime_p(VALUE n)
1563
1614
  {
1564
1615
  VALUE num = ABS(n);
@@ -1570,12 +1621,18 @@ numtheory_bpsw_pseudoprime_p(VALUE n)
1570
1621
  if (LESS(num, two) || EVEN_P(num) ||
1571
1622
  (numtheory_perfect_square_p(num) == Qtrue))
1572
1623
  {
1624
+ #ifdef DEBUG
1625
+ fprintf(stderr, "[bpsw_pseudoprime_p] the number is less than 2, even or a perfect square\n");
1626
+ #endif
1573
1627
  return Qfalse;
1574
1628
  }
1575
1629
 
1576
1630
  // Miller-Rabin test with base 2
1577
1631
  if (miller_rabin_base2_pseudoprime_p(num) == Qfalse)
1578
1632
  {
1633
+ #ifdef DEBUG
1634
+ fprintf(stderr, "[bpsw_pseudoprime_p] Miller-Rabin test with base 2 returned false\n");
1635
+ #endif
1579
1636
  return Qfalse;
1580
1637
  }
1581
1638
 
@@ -1595,7 +1652,10 @@ numtheory_bpsw_pseudoprime_p(VALUE n)
1595
1652
  break;
1596
1653
  }
1597
1654
  }
1598
-
1655
+
1656
+ #ifdef DEBUG
1657
+ fprintf(stderr, "[bpsw_pseudoprime_p] calling Lucas primality test...\n");
1658
+ #endif
1599
1659
  return lucas_pseudoprime_p(num, one, RIGHT_SHIFT(SUB(one, INT2FIX(d)), 2));
1600
1660
  }
1601
1661
 
@@ -1603,6 +1663,8 @@ DEFINE_POWERMOD_SLIDING_WINDOW(int_powermod_sliding_window,
1603
1663
  {},
1604
1664
  MOD)
1605
1665
 
1666
+ #if RUBY_VERSION_MINOR != 8
1606
1667
  DEFINE_POWERMOD_SLIDING_WINDOW(int_powermod_sliding_window_br,
1607
1668
  VALUE mu = rb_big_barrett_mu(m),
1608
1669
  BARRETT_MOD)
1670
+ #endif
@@ -2,52 +2,105 @@
2
2
  #define NUMTHEORY_H
3
3
 
4
4
  #include <ruby.h>
5
- #include <stdio.h>
6
5
  #include <math.h>
7
6
 
7
+ #ifndef HAVE_RUBY_VERSION_H
8
+ #include <version.h>
9
+ #else
10
+ #include <ruby/version.h>
11
+ #endif
12
+
13
+ #if RUBY_VERSION_MINOR == 8
14
+ #include <intern.h>
15
+ #include <defines.h>
16
+ #endif
17
+
18
+ #ifdef DEBUG
19
+ #include <stdio.h>
20
+ inline static char* TO_CSTRING(VALUE x) {
21
+ VALUE v = rb_String(x);
22
+ return StringValueCStr(v);
23
+ }
24
+ #endif
25
+
8
26
  ID id_rand, id_mod, id_divmod, id_div,
9
27
  id_gcd, id_lcm, id_pow, id_mul;
10
28
 
11
29
  extern const VALUE zero,one,two,three,four,five,six,seven,eight;
12
30
 
13
- static VALUE numtheory_powermod(int argc, VALUE *argv);
14
- static VALUE numtheory_miller_rabin_pseudoprime_p(VALUE n);
15
- static VALUE numtheory_nextprime(VALUE n);
16
- static VALUE numtheory_precompute_primes_upto(VALUE obj, VALUE n);
17
- static VALUE numtheory_prime(VALUE obj, VALUE i);
18
- static VALUE numtheory_primepi(VALUE obj, VALUE n);
19
- static VALUE numtheory_fibonacci(int argc, VALUE *argv);
20
- static VALUE numtheory_sigma(int argc, VALUE *argv);
21
- static VALUE numtheory_eulerphi(VALUE obj, VALUE n);
22
- static VALUE numtheory_moebius(VALUE obj, VALUE n);
23
- static VALUE numtheory_prime_division(VALUE n);
24
- static VALUE numtheory_product(VALUE obj, VALUE arr);
25
- static VALUE numtheory_primes_upto(VALUE min, VALUE max);
26
- static VALUE numtheory_factorial_primeswing(VALUE n);
27
- static VALUE numtheory_extended_gcd(VALUE x, VALUE y);
28
- static VALUE numtheory_multiplicative_order(VALUE a, VALUE m);
29
- static VALUE numtheory_pythagorean_triples(VALUE obj, VALUE max_l);
30
- static VALUE numtheory_popcount(VALUE n);
31
- static VALUE numtheory_bitlength(VALUE n);
32
- static VALUE numtheory_sqrtmod(VALUE a, VALUE p);
33
- static VALUE numtheory_isqrt(VALUE n);
34
- static VALUE numtheory_perfect_square_p(VALUE n);
35
- static VALUE numtheory_bpsw_pseudoprime_p(VALUE n);
36
-
37
- static VALUE numtheory_int_powermod(VALUE b, VALUE p, VALUE m);
38
-
39
- static VALUE numtheory_prime_p(VALUE n);
40
- static VALUE numtheory_modular_inverse(VALUE x, VALUE y);
41
- static VALUE numtheory_jacobi(VALUE a, VALUE n);
31
+ VALUE numtheory_powermod(int argc, VALUE *argv);
32
+ VALUE numtheory_miller_rabin_pseudoprime_p(VALUE n);
33
+ VALUE numtheory_nextprime(VALUE n);
34
+ VALUE numtheory_precompute_primes_upto(VALUE obj, VALUE n);
35
+ VALUE numtheory_prime(VALUE obj, VALUE i);
36
+ VALUE numtheory_primepi(VALUE obj, VALUE n);
37
+ VALUE numtheory_fibonacci(int argc, VALUE *argv);
38
+ VALUE numtheory_sigma(int argc, VALUE *argv);
39
+ VALUE numtheory_eulerphi(VALUE obj, VALUE n);
40
+ VALUE numtheory_moebius(VALUE obj, VALUE n);
41
+ VALUE numtheory_prime_division(VALUE n);
42
+ VALUE numtheory_product(VALUE obj, VALUE arr);
43
+ VALUE numtheory_primes_upto(VALUE min, VALUE max);
44
+ VALUE numtheory_factorial_primeswing(VALUE n);
45
+ VALUE numtheory_extended_gcd(VALUE x, VALUE y);
46
+ VALUE numtheory_multiplicative_order(VALUE a, VALUE m);
47
+ VALUE numtheory_pythagorean_triples(VALUE obj, VALUE max_l);
48
+ VALUE numtheory_popcount(VALUE n);
49
+ VALUE numtheory_bitlength(VALUE n);
50
+ VALUE numtheory_sqrtmod(VALUE a, VALUE p);
51
+ VALUE numtheory_isqrt(VALUE n);
52
+ VALUE numtheory_perfect_square_p(VALUE n);
53
+ VALUE numtheory_bpsw_pseudoprime_p(VALUE n);
54
+ VALUE numtheory_int_powermod(VALUE b, VALUE p, VALUE m);
55
+
56
+ VALUE numtheory_prime_p(VALUE n);
57
+ VALUE numtheory_modular_inverse(VALUE x, VALUE y);
58
+ VALUE numtheory_jacobi(VALUE a, VALUE n);
42
59
 
43
60
  #define BITSPERDIG (SIZEOF_BDIGITS * CHAR_BIT)
44
61
  #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
45
62
  #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD - 1)))
46
63
 
64
+ inline static VALUE INT2BIG(long x) {
65
+ return rb_int2big(x);
66
+ }
67
+
68
+ inline static VALUE INTVALUE2BIG(VALUE x) {
69
+ #ifdef DEBUG
70
+ fprintf(stderr, "[intvalue2big] initial value = %s\n", TO_CSTRING(x));
71
+ fprintf(stderr, "[intvalue2big] after conversion to long: %ld\n", FIX2LONG(x));
72
+ fprintf(stderr, "[intvalue2big] after conversion to BIGNUM: %s\n", TO_CSTRING(rb_int2big(FIX2LONG(x))));
73
+ #endif
74
+ return rb_int2big(FIX2LONG(x));
75
+ }
76
+
47
77
  inline static VALUE TO_BIGNUM(VALUE x) {
48
- return FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x;
78
+ return FIXNUM_P(x) ? INTVALUE2BIG(x) : x;
49
79
  }
50
80
 
81
+ #if RUBY_VERSION_MINOR == 8
82
+ static ID id_cmp, id_equal;
83
+
84
+ inline static VALUE rb_big_cmp(VALUE x, VALUE y) {
85
+ return rb_funcall(x, id_cmp, 1, y);
86
+ }
87
+
88
+ inline static int rb_bigzero_p(VALUE x) {
89
+ return rb_funcall(x, id_equal, 1, zero) == Qtrue;
90
+ }
91
+
92
+ inline static VALUE rb_big_eq(VALUE x, VALUE y) {
93
+ return rb_funcall(x, id_equal, 1, y);
94
+ }
95
+
96
+ inline static VALUE rb_big_div(VALUE x, VALUE y) {
97
+ return rb_funcall(x, id_div, 1, y);
98
+ }
99
+ #undef RBIGNUM_DIGITS
100
+ #define RBIGNUM_DIGITS(obj) ((BDIGIT*)(RBIGNUM(obj)->digits))
101
+
102
+ #endif
103
+
51
104
  inline static unsigned long TO_ULONG(VALUE x) {
52
105
  if (!FIXNUM_P(x))
53
106
  {
@@ -80,7 +133,7 @@ inline static VALUE SUB(VALUE x, VALUE y) {
80
133
  rb_big_minus(TO_BIGNUM(x), y);
81
134
  }
82
135
 
83
- #define NEGATE(x) do { if (FIXNUM_P(x)) x = -x; \
136
+ #define NEGATE(x) do { if (FIXNUM_P(x)) x = INT2FIX(-FIX2LONG(x)); \
84
137
  else RBIGNUM_SET_SIGN(x, !RBIGNUM_SIGN(x)); } \
85
138
  while(0);
86
139
 
@@ -107,13 +160,13 @@ inline static VALUE MOD(VALUE x, VALUE y) {
107
160
  inline static int MOD_4(VALUE x) {
108
161
  return FIXNUM_P(x) ? FIX2LONG(x) & 3 :
109
162
  RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 3 :
110
- 4 - RBIGNUM_DIGITS(x)[0] & 3;
163
+ 4 - (RBIGNUM_DIGITS(x)[0] & 3);
111
164
  }
112
165
 
113
166
  inline static int MOD_8(VALUE x) {
114
167
  return FIXNUM_P(x) ? FIX2LONG(x) & 7 :
115
168
  RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 7 :
116
- 8 - RBIGNUM_DIGITS(x)[0] & 7;
169
+ 8 - (RBIGNUM_DIGITS(x)[0] & 7);
117
170
  }
118
171
 
119
172
  inline static int EQL(VALUE x, VALUE y) {
@@ -141,8 +194,14 @@ inline static int MORE_EQL(VALUE x, VALUE y) {
141
194
  }
142
195
 
143
196
  inline static VALUE ABS(VALUE x) {
144
- if (FIXNUM_P(x))
145
- return INT2FIX(abs(FIX2LONG(x)));
197
+ if (FIXNUM_P(x)) {
198
+ #ifdef DEBUG
199
+ fprintf(stderr, "[abs] x = %s\n", TO_CSTRING(x));
200
+ fprintf(stderr, "[abs] FIX2LONG(x) = %ld\n", FIX2LONG(x));
201
+ fprintf(stderr, "[abs] result = %s\n", TO_CSTRING(LONG2FIX(labs(FIX2LONG(x)))));
202
+ #endif
203
+ return LONG2FIX(labs(FIX2LONG(x)));
204
+ }
146
205
  VALUE v = rb_big_clone(x);
147
206
  RBIGNUM_SET_SIGN(v, 1);
148
207
  return v;
@@ -161,8 +220,8 @@ inline static int INTEGER_P(VALUE x) {
161
220
  }
162
221
 
163
222
  inline static VALUE DOUBLED(VALUE x) {
164
- return FIXNUM_P(x) ? LONG2NUM(FIX2LONG(x) << 1) :
165
- rb_big_lshift(x, one);
223
+ return FIXNUM_P(x) ? INT2FIX(FIX2LONG(x) << 1) :
224
+ rb_big_lshift(x, one);
166
225
  }
167
226
 
168
227
  inline static VALUE HALF(VALUE x) {
@@ -180,4 +239,5 @@ inline static VALUE RIGHT_SHIFT(VALUE x, int s) {
180
239
  #endif
181
240
  inline static int min(int a, int b) { return a < b ? a : b; }
182
241
 
242
+
183
243
  #endif
@@ -1,7 +1,10 @@
1
+ #ifndef NUMTHEORY_MACROS_H
2
+ #define NUMTHEORY_MACROS_H 1
3
+
1
4
  #define FOR_PRIME_FACTORS(n, p, d, action) do { \
2
5
  int __d; \
3
- unsigned long __i; \
4
- unsigned long long __t; \
6
+ BDIGIT __i; \
7
+ unsigned LONG_LONG __t; \
5
8
  VALUE __num = (FIXNUM_P(n) ? n : rb_big_clone(n)); \
6
9
  if (!FIXNUM_P(__num)) \
7
10
  { \
@@ -11,7 +14,7 @@
11
14
  } \
12
15
  else \
13
16
  { \
14
- rb_raise(rb_eNotImpError, "Not implemented for numbers >= 2**64"); \
17
+ rb_raise(rb_eNotImpError, "Factorization is not implemented for numbers >= 2**64"); \
15
18
  } \
16
19
  } \
17
20
  else \
@@ -19,7 +22,7 @@
19
22
  __t = FIX2LONG(__num); \
20
23
  } \
21
24
  \
22
- unsigned long long __p; \
25
+ unsigned LONG_LONG __p; \
23
26
  VALUE p, d; \
24
27
  if (prime_p(__t)) \
25
28
  { \
@@ -93,7 +96,7 @@
93
96
  else { \
94
97
  BDIGIT* _digits = RBIGNUM_DIGITS(n); \
95
98
  long _digits_length = RBIGNUM_LEN(n); \
96
- BDIGIT _j; \
99
+ unsigned LONG_LONG _j; \
97
100
  BDIGIT* _digit = _digits + _digits_length - 1; \
98
101
  BDIGIT _half_fst_digit = (*_digit) >> 1; \
99
102
  for (_j = 1; _j <= _half_fst_digit; _j <<= 1); \
@@ -104,7 +107,7 @@
104
107
  else if_zero_action; \
105
108
  final_action; \
106
109
  } \
107
- _j = 1 << (SIZEOF_BDIGITS * 8 - 1); \
110
+ _j = 1ULL << (SIZEOF_BDIGITS * 8 - 1); \
108
111
  } \
109
112
  } \
110
113
  } while(0)
@@ -121,7 +124,7 @@ FUNC_NAME(VALUE b, VALUE p, VALUE m) {\
121
124
  int pow = 0; \
122
125
  \
123
126
  /* adjusting window size */ \
124
- if (FIXNUM_P(p)) p = rb_int2big(FIX2LONG(p)); \
127
+ if (FIXNUM_P(p)) p = INTVALUE2BIG(p); \
125
128
  len = RBIGNUM_LEN(p); \
126
129
  if (len < 8) k = 4; \
127
130
  else if (len < 20) k = 5; \
@@ -199,3 +202,5 @@ FUNC_NAME(VALUE b, VALUE p, VALUE m) {\
199
202
  }
200
203
 
201
204
  #define BARRETT_MOD(x, m) rb_big_barrett_reduce(x, m, mu, 1)
205
+
206
+ #endif
@@ -15,13 +15,12 @@ init_sieve(unsigned long max_n)
15
15
  unset_bit(numtheory_is_prime, 1);
16
16
  numtheory_primes = calloc((long)((double)max_n/(log((double)max_n)-4.0)+1), ULONG_SZ);
17
17
 
18
- unsigned long long i;
19
18
  unsigned long j;
20
19
  unsigned long p = 0;
21
20
  numtheory_primes[p++] = 2;
22
21
  numtheory_primes[p++] = 3;
23
22
 
24
- unsigned long long i1, i2, s;
23
+ unsigned LONG_LONG i1, i2, s;
25
24
  unsigned long max_n_sqrt = (unsigned long)(sqrt((double)max_n));
26
25
 
27
26
  for (i1 = 5, i2 = 7; ; i1 += 6, i2 += 6)
@@ -1,6 +1,8 @@
1
1
  #ifndef NUMTHEORY_PRIMES_H
2
2
  #define NUMTHEORY_PRIMES_H
3
3
 
4
+ #include <ruby.h>
5
+
4
6
  unsigned long init_sieve(unsigned long max_n); // returns prime_pi(max_n)
5
7
 
6
8
  #define ULONG_SZ sizeof(unsigned long)
@@ -1,6 +1,8 @@
1
1
  #include <string.h>
2
2
  #include "numtheory.h"
3
3
 
4
+ #if RUBY_VERSION_MINOR != 8
5
+
4
6
  #define MULADD(i, j) \
5
7
  __asm__ volatile( \
6
8
  "movl %6, %%eax \n\t" \
@@ -31,7 +33,6 @@ inline static VALUE rshift_digits_inplace(VALUE n, int k)
31
33
 
32
34
  BDIGIT* ds = RBIGNUM_DIGITS(n);
33
35
  int len = RBIGNUM_LEN(n);
34
- int i;
35
36
  if (len > k)
36
37
  {
37
38
  memmove(ds, ds + k, SIZEOF_BDIGITS * (len - k));
@@ -47,21 +48,19 @@ inline static VALUE rshift_digits_inplace(VALUE n, int k)
47
48
 
48
49
  inline static VALUE power_of_two(int p)
49
50
  {
50
- return rb_big_lshift(rb_int2big(1), INT2FIX(p));
51
+ return rb_big_lshift(INT2BIG(1), INT2FIX(p));
51
52
  }
52
53
 
53
54
  static VALUE
54
55
  bigmul_low_digits(VALUE x, VALUE y, int digits)
55
56
  {
56
57
  int xn = RBIGNUM_LEN(x);
57
- if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
58
+ if (FIXNUM_P(y)) y = INTVALUE2BIG(y);
58
59
  int yn = RBIGNUM_LEN(y);
59
60
 
60
- int all = 0;
61
61
  if (digits > xn + yn)
62
62
  {
63
63
  digits = xn + yn;
64
- all = 1;
65
64
  }
66
65
  VALUE z = rb_big_new(digits, 1);
67
66
 
@@ -88,7 +87,7 @@ bigmul_low_digits(VALUE x, VALUE y, int digits)
88
87
  VALUE bigmul_low_digits_old(VALUE x, VALUE y, int digits)
89
88
  {
90
89
  int xn = RBIGNUM_LEN(x);
91
- if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
90
+ if (FIXNUM_P(y)) y = INTVALUE2BIG(y);
92
91
  int yn = RBIGNUM_LEN(y);
93
92
  VALUE z = rb_big_new(digits, 1);
94
93
  BDIGIT* xds = RBIGNUM_DIGITS(x);
@@ -120,7 +119,7 @@ static VALUE
120
119
  bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift)
121
120
  {
122
121
  int xn = RBIGNUM_LEN(x);
123
- if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
122
+ if (FIXNUM_P(y)) y = INTVALUE2BIG(y);
124
123
  int yn = RBIGNUM_LEN(y);
125
124
 
126
125
 
@@ -130,7 +129,7 @@ bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift)
130
129
  /* in order to avoid rb_big_clone call,
131
130
  let's virtually "shift" x instead of actual shifting */
132
131
  if (x_right_shift >= xn) {
133
- return rb_int2big(0);
132
+ return INT2BIG(0);
134
133
  } else {
135
134
  xds += x_right_shift;
136
135
  xn -= x_right_shift;
@@ -163,7 +162,7 @@ bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift)
163
162
  VALUE bigmul_high_digits_old(VALUE x, VALUE y, int dontcare)
164
163
  {
165
164
  int xn = RBIGNUM_LEN(x);
166
- if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
165
+ if (FIXNUM_P(y)) y = INTVALUE2BIG(y);
167
166
  int yn = RBIGNUM_LEN(y);
168
167
  VALUE z = rb_big_new(xn + yn, 1);
169
168
  BDIGIT* xds = RBIGNUM_DIGITS(x);
@@ -232,3 +231,5 @@ VALUE rb_big_barrett_reduce(VALUE x, VALUE m, VALUE mu, int inplace)
232
231
  a = SUB(a, m);
233
232
  return rb_big_norm(a);
234
233
  }
234
+
235
+ #endif
@@ -4,8 +4,4 @@
4
4
  VALUE rb_big_barrett_reduce(VALUE,VALUE,VALUE,int);
5
5
  VALUE rb_big_barrett_mu(VALUE);
6
6
 
7
- BDIGIT montgomery_setup(BDIGIT);
8
- VALUE rb_big_montgomery_reduce(VALUE,VALUE,VALUE,int);
9
- BDIGIT small_montgomery_reduce(BDIGIT_DBL, BDIGIT, BDIGIT);
10
-
11
7
  #endif
@@ -3,7 +3,7 @@ Gem::Specification.new do |gem|
3
3
  gem.homepage = "http://github.com/lomereiter/ruby-numtheory"
4
4
  gem.license = "MIT"
5
5
  gem.summary = "Ruby number theory library"
6
- gem.version = "0.0.6"
6
+ gem.version = "0.0.7"
7
7
  gem.platform = Gem::Platform::RUBY
8
8
 
9
9
  gem.description = <<-EOF
@@ -0,0 +1,31 @@
1
+ require 'numtheory'
2
+
3
+ describe "arithmetic function" do
4
+ include NumTheory
5
+
6
+ describe "primepi" do
7
+ it "should raise ArgumentError if there're not enough precomputed primes" do
8
+ expect { primepi(100_000_000_000) }.should raise_error
9
+ end
10
+
11
+ it "should return the number of primes less or equal than a given number" do
12
+ primepi(1).should == 0
13
+ primepi(2).should == 1
14
+ primepi(123512).should == 11607
15
+ primepi(498765).should == 41438
16
+ primepi(312361).should == 26983
17
+ primepi(-123513).should == 0
18
+ end
19
+ end
20
+
21
+ describe "eulerphi" do
22
+ it "should raise ArgumentError if the number is zero" do
23
+ expect { eulerphi(0) }.should raise_error
24
+ end
25
+
26
+ it "should return the number of positive integers less than 'n' and coprime with 'n'" do
27
+ eulerphi(12312361361).should == 11664342324
28
+ eulerphi(12361212371236123).should == 11713214239144000
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ require 'numtheory'
2
+
3
+ describe "bit functions" do
4
+ describe "popcount" do
5
+ it "should return the number of bits set in a non-negative number" do
6
+ 12351231231235091328209183029825132908123295012351.popcount.should == 84
7
+ 82362346211236.popcount.should == 23
8
+ end
9
+
10
+ it "should raise ArgumentError for negative numbers" do
11
+ expect { (-5).popcount }.should raise_error
12
+ expect { (-112351235123512351235).popcount }.should raise_error
13
+ end
14
+ end
15
+
16
+ describe "bitlength" do
17
+ it "should return the length of a positive number in bits" do
18
+ 123512351235125312.bitlength.should == 57
19
+ 12355312.bitlength.should == 24
20
+ 9123616312361235523462346311236136123123136212361.bitlength.should == 163
21
+ end
22
+
23
+ it "should return 1 when argument is 0" do
24
+ 0.bitlength.should == 1
25
+ end
26
+
27
+ it "should raise ArgumentError for negative numbers" do
28
+ expect { (-12351).bitlength }.should raise_error
29
+ expect { (-2039462306492384059132).bitlength }.should raise_error
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ require 'numtheory'
2
+
3
+ describe "Z/pZ" do
4
+
5
+ describe "modular inverse" do
6
+ it "should raise ArgumentError if the inverse doesn't exist" do
7
+ expect { 3.inverse(1236123) }.should raise_error
8
+ expect { 636356661312236113261221231.inverse(71324141236123712312361347131) }.should raise_error
9
+ end
10
+
11
+ it "should return the inverse modulo 'p' if it exists" do
12
+ 170149610396103139612301.inverse(91023960139513512035130519351035).should == 47319168690720853552108144675271
13
+ 10239613261.inverse(1713461351236).should == 1314959799745
14
+ 61235.inverse(13271).should == 10552
15
+ end
16
+ end
17
+
18
+ describe "jacobi symbol (a|n)" do
19
+ it "should raise ArgumentError for negative 'n'" do
20
+ expect { 23.jacobi(-15) }.should raise_error
21
+ end
22
+
23
+ it "should raise ArgumentError for even 'n'" do
24
+ expect { 17.jacobi(24) }.should raise_error
25
+ end
26
+
27
+ it "should return 0 when 'a' and 'n' have common divisors" do
28
+ 25.jacobi(35).should be_zero
29
+ -24.jacobi(9).should be_zero
30
+ 33.jacobi(3).should be_zero
31
+ 128367169183989283691832619381.jacobi(1829631238193612396183612312361231123).should be_zero
32
+ end
33
+
34
+ it "should return 1 when 'a' is a square residue modulo 'n'" do
35
+ 26.jacobi(25).should == 1
36
+ 261235125312351.jacobi(251235123123512351).should == 1
37
+ 123412354123123512351235123512455123.jacobi(12351231236123112351235123523513411).should == 1
38
+ end
39
+
40
+ it "should return -1 in all the other cases" do
41
+ 123412354123123512351235123512455123.jacobi(1235123123612311235123512352351341).should == -1
42
+ 1386136123613661.jacobi(19381923138198391).should == -1
43
+ 2.jacobi(5).should == -1
44
+ 17.jacobi(23).should == -1
45
+ end
46
+ end
47
+
48
+ describe "square root" do
49
+
50
+ it "should raise ArgumentError if 'p' is not a prime number" do
51
+ expect { 7.sqrt_mod(9)}.should raise_error
52
+ end
53
+
54
+ it "should return nil if there is no square root" do
55
+ 33.sqrt_mod(3).should be_nil
56
+ 1231356123521351251.sqrt_mod(123061236013903516123121612316123612379).should be_nil
57
+ end
58
+
59
+ it "should otherwise return the square root from range [0 .. p/2]" do
60
+ 1235112351311.sqrt_mod(123061936032513553).should == 20377270042474840
61
+ 910836013912301293612035135.sqrt_mod(45734753461235122313131523613612412341612361691).should == 17194653522779996910096883279884862754880186510
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,44 @@
1
+ require 'numtheory'
2
+
3
+ describe "primality tests" do
4
+
5
+ describe "prime? method" do
6
+ it "should return exact result for precomputed values" do
7
+ 0.should_not be_prime
8
+ 1.should_not be_prime
9
+ 2.should be_prime
10
+ 3.should be_prime
11
+ 9.should_not be_prime
12
+ -1.should_not be_prime
13
+ -2.should be_prime
14
+ -13.should be_prime
15
+ -16.should_not be_prime
16
+ end
17
+
18
+ it "should apply BPSW test for larger values" do
19
+ 12351236123627.should_not be_prime
20
+ 12351236123659.should be_prime
21
+ 12351236123627123612361235012532906135124234123512356123512342219.should_not be_prime
22
+ 12351236123627123612361235012532906135124234123512356123512342221.should be_prime
23
+ end
24
+
25
+ it "should return true for BPSW pseudoprimes" do
26
+ # no one is found yet :-)
27
+ end
28
+ end
29
+
30
+ describe "miller-rabin test" do
31
+ it "should perform NumTheory::PrimalityTests rounds of Miller-Rabin test" do
32
+ NumTheory.module_eval { remove_const :PrimalityTests }
33
+ NumTheory::PrimalityTests = 1
34
+ srand(100) # MR test uses random base to start
35
+ 671.should be_MR_pseudoprime
36
+ 671.should_not be_BPSW_pseudoprime
37
+
38
+ NumTheory.module_eval { remove_const :PrimalityTests }
39
+ NumTheory::PrimalityTests = 10
40
+ srand(42)
41
+ 671.should_not be_MR_pseudoprime
42
+ end
43
+ end
44
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ruby-numtheory
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.6
5
+ version: 0.0.7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Artem Tarasov
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-08-27 00:00:00 Z
13
+ date: 2012-08-28 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
16
  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"
@@ -23,6 +23,7 @@ extra_rdoc_files:
23
23
  - ext/numtheory/numtheory.c
24
24
  - LICENSE.txt
25
25
  files:
26
+ - .travis.yml
26
27
  - Gemfile
27
28
  - LICENSE.txt
28
29
  - README.md
@@ -32,7 +33,7 @@ files:
32
33
  - ext/numtheory/extconf.rb
33
34
  - ext/numtheory/numtheory.c
34
35
  - ext/numtheory/numtheory.h
35
- - ext/numtheory/numtheory_macros.c
36
+ - ext/numtheory/numtheory_macros.h
36
37
  - ext/numtheory/powermod.h
37
38
  - ext/numtheory/primes.c
38
39
  - ext/numtheory/primes.h
@@ -40,6 +41,10 @@ files:
40
41
  - ext/numtheory/reduce.c
41
42
  - ext/numtheory/reduce.h
42
43
  - ruby-numtheory.gemspec
44
+ - spec/numtheory/arithmetic_functions_spec.rb
45
+ - spec/numtheory/bit_function_spec.rb
46
+ - spec/numtheory/modular_arithmetic_spec.rb
47
+ - spec/numtheory/primality_tests_spec.rb
43
48
  homepage: http://github.com/lomereiter/ruby-numtheory
44
49
  licenses:
45
50
  - MIT
@@ -53,7 +58,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
53
58
  requirements:
54
59
  - - ">="
55
60
  - !ruby/object:Gem::Version
56
- hash: -228771462311290448
61
+ hash: -4196605072839558477
57
62
  segments:
58
63
  - 0
59
64
  version: "0"