ruby-numtheory 0.0.6 → 0.0.7
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.
- data/.travis.yml +4 -0
- data/README.md +2 -0
- data/Rakefile +7 -7
- data/ext/numtheory/extconf.rb +1 -1
- data/ext/numtheory/numtheory.c +118 -56
- data/ext/numtheory/numtheory.h +98 -38
- data/ext/numtheory/{numtheory_macros.c → numtheory_macros.h} +12 -7
- data/ext/numtheory/primes.c +1 -2
- data/ext/numtheory/primes.h +2 -0
- data/ext/numtheory/reduce.c +10 -9
- data/ext/numtheory/reduce.h +0 -4
- data/ruby-numtheory.gemspec +1 -1
- data/spec/numtheory/arithmetic_functions_spec.rb +31 -0
- data/spec/numtheory/bit_function_spec.rb +32 -0
- data/spec/numtheory/modular_arithmetic_spec.rb +64 -0
- data/spec/numtheory/primality_tests_spec.rb +44 -0
- metadata +9 -4
data/.travis.yml
ADDED
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
|
+
[](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
|
-
|
23
|
-
|
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
|
data/ext/numtheory/extconf.rb
CHANGED
data/ext/numtheory/numtheory.c
CHANGED
@@ -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
|
-
#
|
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
|
-
|
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
|
-
|
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) ?
|
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
|
-
|
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
|
-
|
255
|
-
|
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,
|
265
|
-
|
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
|
-
|
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(
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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;
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
825
|
+
VALUE
|
800
826
|
numtheory_product(VALUE obj, VALUE arr)
|
801
827
|
{
|
802
|
-
if (
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1198
|
+
long_bitlength(unsigned long v)
|
1169
1199
|
{
|
1170
|
-
|
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
|
-
|
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
|
-
|
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
|
1239
|
+
long bit_len;
|
1202
1240
|
if (FIXNUM_P(n))
|
1203
1241
|
{
|
1204
|
-
return INT2FIX(
|
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 +
|
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(
|
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
|
-
|
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 > (
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/ext/numtheory/numtheory.h
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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) ?
|
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
|
-
|
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) ?
|
165
|
-
|
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
|
-
|
4
|
-
unsigned
|
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, "
|
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
|
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
|
-
|
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 =
|
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 =
|
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
|
data/ext/numtheory/primes.c
CHANGED
@@ -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
|
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)
|
data/ext/numtheory/primes.h
CHANGED
data/ext/numtheory/reduce.c
CHANGED
@@ -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(
|
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 =
|
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 =
|
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 =
|
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
|
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 =
|
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
|
data/ext/numtheory/reduce.h
CHANGED
data/ruby-numtheory.gemspec
CHANGED
@@ -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
|
+
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.
|
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-
|
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.
|
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: -
|
61
|
+
hash: -4196605072839558477
|
57
62
|
segments:
|
58
63
|
- 0
|
59
64
|
version: "0"
|