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 +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
|
+
[![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
|
-
|
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"
|