ruby-numtheory 0.0.5 → 0.0.6

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.
@@ -0,0 +1,183 @@
1
+ #ifndef NUMTHEORY_H
2
+ #define NUMTHEORY_H
3
+
4
+ #include <ruby.h>
5
+ #include <stdio.h>
6
+ #include <math.h>
7
+
8
+ ID id_rand, id_mod, id_divmod, id_div,
9
+ id_gcd, id_lcm, id_pow, id_mul;
10
+
11
+ extern const VALUE zero,one,two,three,four,five,six,seven,eight;
12
+
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);
42
+
43
+ #define BITSPERDIG (SIZEOF_BDIGITS * CHAR_BIT)
44
+ #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
45
+ #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD - 1)))
46
+
47
+ inline static VALUE TO_BIGNUM(VALUE x) {
48
+ return FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x;
49
+ }
50
+
51
+ inline static unsigned long TO_ULONG(VALUE x) {
52
+ if (!FIXNUM_P(x))
53
+ {
54
+ if (rb_big_cmp(x, ULONG2NUM(ULONG_MAX)) != one)
55
+ return rb_big2ulong(x);
56
+ else
57
+ rb_raise(rb_eNotImpError, "Not implemented for numbers >= 2**32");
58
+ }
59
+ return FIX2ULONG(x);
60
+ }
61
+
62
+ inline static int EVEN_P(VALUE x) {
63
+ return FIXNUM_P(x) ? !(FIX2ULONG(x)&1) : !(RBIGNUM_DIGITS(x)[0]&1);
64
+ }
65
+
66
+ inline static int ZERO_P(VALUE x) {
67
+ return FIXNUM_P(x) ? FIX2LONG(x) == 0 : rb_bigzero_p(x);
68
+ }
69
+
70
+ inline static VALUE ADD(VALUE x, VALUE y) {
71
+ return FIXNUM_P(x) ? FIXNUM_P(y) ?
72
+ LONG2NUM(FIX2LONG(x) + FIX2LONG(y)) :
73
+ rb_big_plus(y, x) :
74
+ rb_big_plus(x, y);
75
+ }
76
+
77
+ inline static VALUE SUB(VALUE x, VALUE y) {
78
+ return (FIXNUM_P(x) && FIXNUM_P(y)) ?
79
+ LONG2NUM(FIX2LONG(x) - FIX2LONG(y)) :
80
+ rb_big_minus(TO_BIGNUM(x), y);
81
+ }
82
+
83
+ #define NEGATE(x) do { if (FIXNUM_P(x)) x = -x; \
84
+ else RBIGNUM_SET_SIGN(x, !RBIGNUM_SIGN(x)); } \
85
+ while(0);
86
+
87
+ inline static VALUE MUL(VALUE x, VALUE y) {
88
+ return rb_funcall(x, id_mul, 1, y);
89
+ }
90
+
91
+ inline static VALUE POW(VALUE b, VALUE p) {
92
+ return rb_funcall(b, id_pow, 1, p);
93
+ }
94
+
95
+ inline static VALUE DIV(VALUE x, VALUE y) {
96
+ return rb_funcall(x, id_div, 1, y);
97
+ }
98
+
99
+ inline static VALUE DIVMOD(VALUE x, VALUE y) {
100
+ return rb_funcall(x, id_divmod, 1, y);
101
+ }
102
+
103
+ inline static VALUE MOD(VALUE x, VALUE y) {
104
+ return rb_funcall(x, id_mod, 1, y);
105
+ }
106
+
107
+ inline static int MOD_4(VALUE x) {
108
+ return FIXNUM_P(x) ? FIX2LONG(x) & 3 :
109
+ RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 3 :
110
+ 4 - RBIGNUM_DIGITS(x)[0] & 3;
111
+ }
112
+
113
+ inline static int MOD_8(VALUE x) {
114
+ return FIXNUM_P(x) ? FIX2LONG(x) & 7 :
115
+ RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 7 :
116
+ 8 - RBIGNUM_DIGITS(x)[0] & 7;
117
+ }
118
+
119
+ inline static int EQL(VALUE x, VALUE y) {
120
+ return (FIXNUM_P(x) && FIXNUM_P(y)) ?
121
+ x == y :
122
+ rb_big_eq(TO_BIGNUM(x), y) == Qtrue;
123
+ }
124
+
125
+ inline static int MORE(VALUE x, VALUE y) {
126
+ return (FIXNUM_P(x) && FIXNUM_P(y)) ?
127
+ FIX2LONG(x) > FIX2LONG(y) :
128
+ rb_big_cmp(TO_BIGNUM(x), y) == one;
129
+ }
130
+
131
+ inline static int LESS(VALUE x, VALUE y) {
132
+ return (FIXNUM_P(x) && FIXNUM_P(y)) ?
133
+ FIX2LONG(x) < FIX2LONG(y) :
134
+ rb_big_cmp(TO_BIGNUM(x), y) == INT2FIX(-1);
135
+ }
136
+
137
+ inline static int MORE_EQL(VALUE x, VALUE y) {
138
+ return (FIXNUM_P(x) && FIXNUM_P(y)) ?
139
+ FIX2LONG(x) >= FIX2LONG(y) :
140
+ rb_big_cmp(TO_BIGNUM(x), y) != INT2FIX(-1);
141
+ }
142
+
143
+ inline static VALUE ABS(VALUE x) {
144
+ if (FIXNUM_P(x))
145
+ return INT2FIX(abs(FIX2LONG(x)));
146
+ VALUE v = rb_big_clone(x);
147
+ RBIGNUM_SET_SIGN(v, 1);
148
+ return v;
149
+ }
150
+
151
+ inline static int NEGATIVE_P(VALUE x) {
152
+ return FIXNUM_P(x) ? FIX2LONG(x) < 0 : RBIGNUM_NEGATIVE_P(x);
153
+ }
154
+
155
+ inline static VALUE CLONE(VALUE x) {
156
+ return FIXNUM_P(x) ? x : rb_big_clone(x);
157
+ }
158
+
159
+ inline static int INTEGER_P(VALUE x) {
160
+ return (TYPE(x) == T_FIXNUM) || (TYPE(x) == T_BIGNUM);
161
+ }
162
+
163
+ inline static VALUE DOUBLED(VALUE x) {
164
+ return FIXNUM_P(x) ? LONG2NUM(FIX2LONG(x) << 1) :
165
+ rb_big_lshift(x, one);
166
+ }
167
+
168
+ inline static VALUE HALF(VALUE x) {
169
+ return FIXNUM_P(x) ? INT2FIX(FIX2LONG(x) >> 1) :
170
+ rb_big_rshift(x, one);
171
+ }
172
+
173
+ inline static VALUE RIGHT_SHIFT(VALUE x, int s) {
174
+ return FIXNUM_P(x) ? INT2FIX(FIX2LONG(x) >> s) :
175
+ rb_big_rshift(x, INT2FIX(s));
176
+ }
177
+
178
+ #ifdef min
179
+ #undef min
180
+ #endif
181
+ inline static int min(int a, int b) { return a < b ? a : b; }
182
+
183
+ #endif
@@ -0,0 +1,201 @@
1
+ #define FOR_PRIME_FACTORS(n, p, d, action) do { \
2
+ int __d; \
3
+ unsigned long __i; \
4
+ unsigned long long __t; \
5
+ VALUE __num = (FIXNUM_P(n) ? n : rb_big_clone(n)); \
6
+ if (!FIXNUM_P(__num)) \
7
+ { \
8
+ if (rb_big_cmp(__num, ULL2NUM(ULLONG_MAX)) != INT2FIX(1)) \
9
+ { \
10
+ __t = rb_big2ull(__num); \
11
+ } \
12
+ else \
13
+ { \
14
+ rb_raise(rb_eNotImpError, "Not implemented for numbers >= 2**64"); \
15
+ } \
16
+ } \
17
+ else \
18
+ { \
19
+ __t = FIX2LONG(__num); \
20
+ } \
21
+ \
22
+ unsigned long long __p; \
23
+ VALUE p, d; \
24
+ if (prime_p(__t)) \
25
+ { \
26
+ d = INT2FIX(1); \
27
+ p = ULL2NUM(__t); \
28
+ action; \
29
+ __t = 1; \
30
+ break; \
31
+ } \
32
+ for (__i = 0; (__i < NUM_OF_PRIMES) && (__t > 1); ++__i) \
33
+ { \
34
+ __p = numtheory_primes[__i]; \
35
+ if (__p * __p > __t) \
36
+ { \
37
+ d = INT2FIX(1); \
38
+ __p = __t; \
39
+ p = ULL2NUM(__p); \
40
+ action; \
41
+ __t = 1; \
42
+ break; \
43
+ } \
44
+ if (__t % __p == 0) \
45
+ { \
46
+ __d = 0; \
47
+ do { \
48
+ __t /= __p; \
49
+ ++__d; \
50
+ } while (!(__t % __p)); \
51
+ p = ULL2NUM(__p); \
52
+ d = INT2FIX(__d); \
53
+ action; \
54
+ \
55
+ if (prime_p(__t)) \
56
+ { \
57
+ d = INT2FIX(1); \
58
+ p = ULL2NUM(__t); \
59
+ action; \
60
+ __t = 1; \
61
+ break; \
62
+ } \
63
+ } \
64
+ } \
65
+ if (__t != 1) \
66
+ { \
67
+ p = ULL2NUM(__t); \
68
+ if (numtheory_prime_p(p) == Qtrue) \
69
+ { \
70
+ d = INT2FIX(1); \
71
+ action; \
72
+ } \
73
+ else \
74
+ { \
75
+ raise_not_enough_exception(); \
76
+ } \
77
+ } \
78
+ } while(0)
79
+
80
+ #define FOR_BITS(n, before_action, if_zero_action, if_one_action, final_action) do { \
81
+ if (FIXNUM_P(n)) { \
82
+ long _pow = FIX2LONG(n); \
83
+ long _half_p = _pow >> 1; \
84
+ long _j = 1; \
85
+ for( ; _j <= _half_p; _j <<= 1 ); \
86
+ for( ; _j ; _j >>= 1) { \
87
+ before_action; \
88
+ if (_pow & _j) do { if_one_action; } while(0); \
89
+ else if_zero_action; \
90
+ final_action; \
91
+ } \
92
+ } \
93
+ else { \
94
+ BDIGIT* _digits = RBIGNUM_DIGITS(n); \
95
+ long _digits_length = RBIGNUM_LEN(n); \
96
+ BDIGIT _j; \
97
+ BDIGIT* _digit = _digits + _digits_length - 1; \
98
+ BDIGIT _half_fst_digit = (*_digit) >> 1; \
99
+ for (_j = 1; _j <= _half_fst_digit; _j <<= 1); \
100
+ for (; _digit >= _digits; --_digit) { \
101
+ for (; _j > 0; _j >>= 1){ \
102
+ before_action; \
103
+ if (*_digit & _j) do { if_one_action; } while(0); \
104
+ else if_zero_action; \
105
+ final_action; \
106
+ } \
107
+ _j = 1 << (SIZEOF_BDIGITS * 8 - 1); \
108
+ } \
109
+ } \
110
+ } while(0)
111
+
112
+ #define DEFINE_POWERMOD_SLIDING_WINDOW(FUNC_NAME, REDUCE_PROLOGUE, REDUCE_METHOD) \
113
+ static VALUE \
114
+ FUNC_NAME(VALUE b, VALUE p, VALUE m) {\
115
+ VALUE result = one; \
116
+ enum { squaring, collecting } state; \
117
+ \
118
+ state = collecting; \
119
+ int len, k; \
120
+ int zeros = 0; \
121
+ int pow = 0; \
122
+ \
123
+ /* adjusting window size */ \
124
+ if (FIXNUM_P(p)) p = rb_int2big(FIX2LONG(p)); \
125
+ len = RBIGNUM_LEN(p); \
126
+ if (len < 8) k = 4; \
127
+ else if (len < 20) k = 5; \
128
+ else if (len < 48) k = 6; \
129
+ else if (len < 120) k = 7; \
130
+ else k = 8; \
131
+ \
132
+ len = 0; \
133
+ \
134
+ REDUCE_PROLOGUE; \
135
+ \
136
+ b = MOD(b, m); /* necessary because for Barrett reduction to work \
137
+ b must be less than m^2 */ \
138
+ \
139
+ VALUE b_squared = REDUCE_METHOD(MUL(b, b), m); \
140
+ VALUE *powers = ALLOCA_N(VALUE, 1<<(k-1)); \
141
+ powers[0] = b; \
142
+ \
143
+ int i; \
144
+ /* precomputation of odd powers; \
145
+ powers[n] = (b ** (2n + 1)) % m */ \
146
+ for (i = 1; i < (1<<(k-1)); ++i) \
147
+ powers[i] = REDUCE_METHOD(MUL(powers[i-1], b_squared), m); \
148
+ \
149
+ FOR_BITS(p, {}, \
150
+ { /* if the bit is zero */ \
151
+ if (state == collecting) { \
152
+ ++ len; \
153
+ ++ zeros; \
154
+ pow <<= 1; \
155
+ if (len == k) { \
156
+ pow >>= zeros; \
157
+ \
158
+ for (i = len; i > zeros; i--) \
159
+ result = REDUCE_METHOD(MUL(result, result), m); \
160
+ result = REDUCE_METHOD(MUL(result, powers[pow>>1]), m); \
161
+ while (zeros--) \
162
+ result = REDUCE_METHOD(MUL(result, result), m); \
163
+ \
164
+ state = squaring; pow = len = zeros = 0; \
165
+ } \
166
+ } else { \
167
+ result = REDUCE_METHOD(MUL(result, result), m); \
168
+ } \
169
+ }, \
170
+ { /* the bit is one */ \
171
+ if (state == collecting) { \
172
+ ++ len; \
173
+ zeros = 0; \
174
+ pow = (pow << 1) + 1; \
175
+ if (len == k) { \
176
+ while (len--) \
177
+ result = REDUCE_METHOD(MUL(result, result), m); \
178
+ result = REDUCE_METHOD(MUL(result, powers[pow>>1]), m); \
179
+ state = squaring; \
180
+ pow = len = 0; \
181
+ } \
182
+ } else { \
183
+ state = collecting; \
184
+ pow = 1; \
185
+ len = 1; \
186
+ zeros = 0; \
187
+ } \
188
+ }, {}); \
189
+ if (len > 0) { \
190
+ pow >>= zeros; \
191
+ \
192
+ for (i = len; i > zeros; i--) \
193
+ result = REDUCE_METHOD(MUL(result, result), m); \
194
+ result = REDUCE_METHOD(MUL(result, powers[pow>>1]), m); \
195
+ while (zeros--) \
196
+ result = REDUCE_METHOD(MUL(result, result), m); \
197
+ } \
198
+ return result; \
199
+ }
200
+
201
+ #define BARRETT_MOD(x, m) rb_big_barrett_reduce(x, m, mu, 1)
@@ -0,0 +1,9 @@
1
+ #ifndef NUMTHEORY_POWERMOD_H
2
+ #define NUMTHEORY_POWERMOD_H
3
+
4
+ BDIGIT int_powermod_montgomery_small(VALUE, VALUE, BDIGIT);
5
+ VALUE int_powermod_sliding_window(VALUE, VALUE, VALUE);
6
+ VALUE int_powermod_sliding_window_br(VALUE, VALUE, VALUE);
7
+ VALUE int_powermod_sliding_window_mont(VALUE, VALUE, VALUE);
8
+
9
+ #endif
@@ -0,0 +1,57 @@
1
+ #include <math.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include "primes.h"
5
+
6
+ unsigned long *numtheory_is_prime; // n = 2k+1 -> k-th bit
7
+ unsigned long *numtheory_primes;
8
+
9
+ unsigned long
10
+ init_sieve(unsigned long max_n)
11
+ {
12
+ size_t is_p_sz = max_n / (2 * ULONG_SZ) + 1;
13
+ numtheory_is_prime = malloc(is_p_sz * ULONG_SZ);
14
+ memset(numtheory_is_prime, 0xFFFFFFFF, is_p_sz * ULONG_SZ);
15
+ unset_bit(numtheory_is_prime, 1);
16
+ numtheory_primes = calloc((long)((double)max_n/(log((double)max_n)-4.0)+1), ULONG_SZ);
17
+
18
+ unsigned long long i;
19
+ unsigned long j;
20
+ unsigned long p = 0;
21
+ numtheory_primes[p++] = 2;
22
+ numtheory_primes[p++] = 3;
23
+
24
+ unsigned long long i1, i2, s;
25
+ unsigned long max_n_sqrt = (unsigned long)(sqrt((double)max_n));
26
+
27
+ for (i1 = 5, i2 = 7; ; i1 += 6, i2 += 6)
28
+ {
29
+ if (i1 > max_n_sqrt) break;
30
+ if (is_set(numtheory_is_prime, i1))
31
+ {
32
+ s = i1 << 1;
33
+ for (j = i1 * i1; j <= max_n; j += s)
34
+ unset_bit(numtheory_is_prime, j);
35
+ numtheory_primes[p++] = i1;
36
+ }
37
+ if (i2 > max_n_sqrt) break;
38
+ if (is_set(numtheory_is_prime, i2))
39
+ {
40
+ s = i2 << 1;
41
+ for (j = i2 * i2; j <= max_n; j += s)
42
+ unset_bit(numtheory_is_prime, j);
43
+ numtheory_primes[p++] = i2;
44
+ }
45
+ }
46
+ for ( ; ; i1 += 6, i2 += 6)
47
+ {
48
+ if (i1 > max_n) break;
49
+ if (is_set(numtheory_is_prime, i1))
50
+ numtheory_primes[p++] = i1;
51
+ if (i2 > max_n) break;
52
+ if (is_set(numtheory_is_prime, i2))
53
+ numtheory_primes[p++] = i2;
54
+ }
55
+ numtheory_primes = realloc(numtheory_primes, p * ULONG_SZ);
56
+ return p;
57
+ }