ruby-numtheory 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/LICENSE.txt +20 -0
- data/README.md +22 -0
- data/Rakefile +34 -0
- data/ext/numtheory/Makefile +187 -0
- data/ext/numtheory/constants.h +24 -0
- data/ext/numtheory/extconf.rb +1 -0
- data/ext/numtheory/numtheory.c +45 -281
- data/ext/numtheory/numtheory.h +183 -0
- data/ext/numtheory/numtheory_macros.c +201 -0
- data/ext/numtheory/powermod.h +9 -0
- data/ext/numtheory/primes.c +57 -0
- data/ext/numtheory/primes.h +25 -0
- data/ext/numtheory/queue.h +63 -0
- data/ext/numtheory/reduce.c +234 -0
- data/ext/numtheory/reduce.h +11 -0
- data/ruby-numtheory.gemspec +24 -0
- metadata +29 -22
@@ -0,0 +1,25 @@
|
|
1
|
+
#ifndef NUMTHEORY_PRIMES_H
|
2
|
+
#define NUMTHEORY_PRIMES_H
|
3
|
+
|
4
|
+
unsigned long init_sieve(unsigned long max_n); // returns prime_pi(max_n)
|
5
|
+
|
6
|
+
#define ULONG_SZ sizeof(unsigned long)
|
7
|
+
|
8
|
+
extern unsigned long *numtheory_is_prime;
|
9
|
+
extern unsigned long *numtheory_primes;
|
10
|
+
|
11
|
+
static inline unsigned long
|
12
|
+
is_set(unsigned long* ary, unsigned long n)
|
13
|
+
{
|
14
|
+
long k = n >> 1;
|
15
|
+
return ary[k / ULONG_SZ] & (1 << (k & (ULONG_SZ - 1)));
|
16
|
+
}
|
17
|
+
|
18
|
+
static inline void
|
19
|
+
unset_bit(unsigned long* ary, unsigned long n)
|
20
|
+
{
|
21
|
+
long k = n >> 1;
|
22
|
+
ary[k / ULONG_SZ] &= ~(1 << (k & (ULONG_SZ - 1)));
|
23
|
+
}
|
24
|
+
|
25
|
+
#endif
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#ifndef NUMTHEORY_QUEUE_H
|
2
|
+
#define NUMTHEORY_QUEUE_H
|
3
|
+
|
4
|
+
#include <stdlib.h>
|
5
|
+
|
6
|
+
typedef struct Node Node;
|
7
|
+
struct Node {
|
8
|
+
void* val;
|
9
|
+
Node* next;
|
10
|
+
};
|
11
|
+
|
12
|
+
typedef struct {
|
13
|
+
Node* first;
|
14
|
+
Node* last;
|
15
|
+
} Queue;
|
16
|
+
|
17
|
+
static inline Queue* queue_new()
|
18
|
+
{
|
19
|
+
Queue* q;
|
20
|
+
q = malloc(sizeof(Queue));
|
21
|
+
q -> first = q -> last = NULL;
|
22
|
+
return q;
|
23
|
+
}
|
24
|
+
|
25
|
+
static inline void queue_push(Queue* q, void* elem)
|
26
|
+
{
|
27
|
+
Node* new_node = malloc(sizeof(Node));
|
28
|
+
new_node -> val = elem;
|
29
|
+
new_node -> next = NULL;
|
30
|
+
if (q -> last)
|
31
|
+
{
|
32
|
+
q -> last -> next = new_node;
|
33
|
+
}
|
34
|
+
else
|
35
|
+
{
|
36
|
+
q -> first = new_node;
|
37
|
+
}
|
38
|
+
q -> last = new_node;
|
39
|
+
}
|
40
|
+
|
41
|
+
static inline void* queue_pop(Queue* q)
|
42
|
+
{
|
43
|
+
if (q -> first == NULL)
|
44
|
+
{
|
45
|
+
return NULL;
|
46
|
+
}
|
47
|
+
Node* fst_node = q -> first;
|
48
|
+
void* elem = fst_node -> val;
|
49
|
+
q -> first = fst_node -> next;
|
50
|
+
if (q -> first == NULL)
|
51
|
+
{
|
52
|
+
q -> last = NULL;
|
53
|
+
}
|
54
|
+
free(fst_node);
|
55
|
+
return elem;
|
56
|
+
}
|
57
|
+
|
58
|
+
static inline int queue_empty(Queue* q)
|
59
|
+
{
|
60
|
+
return q -> first == NULL;
|
61
|
+
}
|
62
|
+
|
63
|
+
#endif
|
@@ -0,0 +1,234 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include "numtheory.h"
|
3
|
+
|
4
|
+
#define MULADD(i, j) \
|
5
|
+
__asm__ volatile( \
|
6
|
+
"movl %6, %%eax \n\t" \
|
7
|
+
"mull %7 \n\t" \
|
8
|
+
"addl %%eax, %0 \n\t" \
|
9
|
+
"adcl %%edx, %1 \n\t" \
|
10
|
+
"adcl $0, %2 \n\t" : \
|
11
|
+
"=m"(c0), "=m"(c1), "=m"(c2) : \
|
12
|
+
"m"(c0), "m"(c1), "m"(c2), "m"(i), "m"(j) : \
|
13
|
+
"%eax","%edx", "%cc");
|
14
|
+
|
15
|
+
#define BITSPERDIG (SIZEOF_BDIGITS * CHAR_BIT)
|
16
|
+
#define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
|
17
|
+
#define BIGLO(x) ((BDIGIT)((x) & (BIGRAD - 1)))
|
18
|
+
|
19
|
+
#define RBIGNUM_SET_LEN(b,l) \
|
20
|
+
((RBASIC(b)->flags & RBIGNUM_EMBED_FLAG) ? \
|
21
|
+
(void)(RBASIC(b)->flags = \
|
22
|
+
(RBASIC(b)->flags & ~RBIGNUM_EMBED_LEN_MASK) | \
|
23
|
+
((l) << RBIGNUM_EMBED_LEN_SHIFT)) : \
|
24
|
+
(void)(RBIGNUM(b)->as.heap.len = (l)))
|
25
|
+
|
26
|
+
inline static VALUE rshift_digits_inplace(VALUE n, int k)
|
27
|
+
{
|
28
|
+
if (FIXNUM_P(n)) {
|
29
|
+
return INT2FIX(0);
|
30
|
+
}
|
31
|
+
|
32
|
+
BDIGIT* ds = RBIGNUM_DIGITS(n);
|
33
|
+
int len = RBIGNUM_LEN(n);
|
34
|
+
int i;
|
35
|
+
if (len > k)
|
36
|
+
{
|
37
|
+
memmove(ds, ds + k, SIZEOF_BDIGITS * (len - k));
|
38
|
+
RBIGNUM_SET_LEN(n, len - k);
|
39
|
+
return n;
|
40
|
+
}
|
41
|
+
else
|
42
|
+
{
|
43
|
+
RBIGNUM_SET_LEN(n, 0);
|
44
|
+
return n;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
inline static VALUE power_of_two(int p)
|
49
|
+
{
|
50
|
+
return rb_big_lshift(rb_int2big(1), INT2FIX(p));
|
51
|
+
}
|
52
|
+
|
53
|
+
static VALUE
|
54
|
+
bigmul_low_digits(VALUE x, VALUE y, int digits)
|
55
|
+
{
|
56
|
+
int xn = RBIGNUM_LEN(x);
|
57
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
58
|
+
int yn = RBIGNUM_LEN(y);
|
59
|
+
|
60
|
+
int all = 0;
|
61
|
+
if (digits > xn + yn)
|
62
|
+
{
|
63
|
+
digits = xn + yn;
|
64
|
+
all = 1;
|
65
|
+
}
|
66
|
+
VALUE z = rb_big_new(digits, 1);
|
67
|
+
|
68
|
+
BDIGIT* xds = RBIGNUM_DIGITS(x);
|
69
|
+
BDIGIT* yds = RBIGNUM_DIGITS(y);
|
70
|
+
BDIGIT* zds = RBIGNUM_DIGITS(z);
|
71
|
+
|
72
|
+
BDIGIT c0,c1,c2; // carry
|
73
|
+
int i, j, k, beg, end;
|
74
|
+
for (k = c0 = c1 = c2 = 0; k < digits; k++)
|
75
|
+
{
|
76
|
+
beg = k >= yn - 1 ? k - yn + 1 : 0;
|
77
|
+
end = k >= xn ? xn - 1 : k;
|
78
|
+
for (i = beg, j = k - beg; i <= end; ++i, --j)
|
79
|
+
MULADD(xds[i], yds[j]);
|
80
|
+
zds[k] = c0;
|
81
|
+
c0 = c1;
|
82
|
+
c1 = c2;
|
83
|
+
c2 = 0;
|
84
|
+
}
|
85
|
+
return rb_big_norm(z);
|
86
|
+
}
|
87
|
+
/*
|
88
|
+
VALUE bigmul_low_digits_old(VALUE x, VALUE y, int digits)
|
89
|
+
{
|
90
|
+
int xn = RBIGNUM_LEN(x);
|
91
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
92
|
+
int yn = RBIGNUM_LEN(y);
|
93
|
+
VALUE z = rb_big_new(digits, 1);
|
94
|
+
BDIGIT* xds = RBIGNUM_DIGITS(x);
|
95
|
+
BDIGIT* yds = RBIGNUM_DIGITS(y);
|
96
|
+
BDIGIT* zds = RBIGNUM_DIGITS(z);
|
97
|
+
|
98
|
+
int i, j, k;
|
99
|
+
for (i = 0; i < digits; zds[i++] = 0);
|
100
|
+
BDIGIT_DBL dd, carry;
|
101
|
+
for (i = 0; i < xn; ++i)
|
102
|
+
{
|
103
|
+
dd = xds[i];
|
104
|
+
carry = 0;
|
105
|
+
k = digits - i;
|
106
|
+
if (k > yn) k = yn;
|
107
|
+
for (j = 0; j < k; ++j)
|
108
|
+
{
|
109
|
+
carry += dd * yds[j] + zds[i + j];
|
110
|
+
zds[i + j] = BIGLO(carry);
|
111
|
+
carry >>= BITSPERDIG;
|
112
|
+
}
|
113
|
+
if (carry && (i + j) < digits)
|
114
|
+
zds[i + j] = carry;
|
115
|
+
}
|
116
|
+
return rb_big_norm(z);
|
117
|
+
} */
|
118
|
+
|
119
|
+
static VALUE
|
120
|
+
bigmul_high_digits(VALUE x, VALUE y, int dontcare, int x_right_shift)
|
121
|
+
{
|
122
|
+
int xn = RBIGNUM_LEN(x);
|
123
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
124
|
+
int yn = RBIGNUM_LEN(y);
|
125
|
+
|
126
|
+
|
127
|
+
BDIGIT* xds = RBIGNUM_DIGITS(x);
|
128
|
+
BDIGIT* yds = RBIGNUM_DIGITS(y);
|
129
|
+
|
130
|
+
/* in order to avoid rb_big_clone call,
|
131
|
+
let's virtually "shift" x instead of actual shifting */
|
132
|
+
if (x_right_shift >= xn) {
|
133
|
+
return rb_int2big(0);
|
134
|
+
} else {
|
135
|
+
xds += x_right_shift;
|
136
|
+
xn -= x_right_shift;
|
137
|
+
}
|
138
|
+
|
139
|
+
int digits = xn + yn;
|
140
|
+
int i, j, k;
|
141
|
+
VALUE z = rb_big_new(digits, 1);
|
142
|
+
BDIGIT* zds = RBIGNUM_DIGITS(z);
|
143
|
+
for (i = 0; i < digits; zds[i++] = 0);
|
144
|
+
|
145
|
+
int beg, end;
|
146
|
+
|
147
|
+
BDIGIT c0, c1, c2;
|
148
|
+
for (k = dontcare, c0 = c1 = c2 = 0; k < digits; k++)
|
149
|
+
{
|
150
|
+
beg = k >= yn - 1 ? k - yn + 1 : 0;
|
151
|
+
end = k >= xn ? xn - 1 : k;
|
152
|
+
for (i = beg, j = k - beg; i <= end; ++i, --j)
|
153
|
+
MULADD(xds[i], yds[j]);
|
154
|
+
zds[k] = c0;
|
155
|
+
c0 = c1;
|
156
|
+
c1 = c2;
|
157
|
+
c2 = 0;
|
158
|
+
}
|
159
|
+
return z;
|
160
|
+
}
|
161
|
+
|
162
|
+
/*
|
163
|
+
VALUE bigmul_high_digits_old(VALUE x, VALUE y, int dontcare)
|
164
|
+
{
|
165
|
+
int xn = RBIGNUM_LEN(x);
|
166
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
167
|
+
int yn = RBIGNUM_LEN(y);
|
168
|
+
VALUE z = rb_big_new(xn + yn, 1);
|
169
|
+
BDIGIT* xds = RBIGNUM_DIGITS(x);
|
170
|
+
BDIGIT* yds = RBIGNUM_DIGITS(y);
|
171
|
+
BDIGIT* zds = RBIGNUM_DIGITS(z);
|
172
|
+
|
173
|
+
int i, j, k;
|
174
|
+
for (i = 0; i < xn + yn; zds[i++] = 0);
|
175
|
+
BDIGIT_DBL dd, carry;
|
176
|
+
for (i = 0; i < xn; ++i)
|
177
|
+
{
|
178
|
+
dd = xds[i];
|
179
|
+
carry = 0;
|
180
|
+
k = dontcare - i;
|
181
|
+
if (k < 0) k = 0;
|
182
|
+
for (j = k; j < yn; ++j)
|
183
|
+
{
|
184
|
+
carry += dd * yds[j] + zds[i + j];
|
185
|
+
zds[i + j] = BIGLO(carry);
|
186
|
+
carry >>= BITSPERDIG;
|
187
|
+
}
|
188
|
+
if (i+j >= dontcare)
|
189
|
+
zds[i+j] = carry;
|
190
|
+
}
|
191
|
+
return z;
|
192
|
+
}*/
|
193
|
+
|
194
|
+
|
195
|
+
VALUE rb_big_barrett_mu(VALUE m)
|
196
|
+
{
|
197
|
+
long len = RBIGNUM_LEN(m);
|
198
|
+
return rb_big_div(power_of_two(2 * len * BITSPERDIG), m);
|
199
|
+
}
|
200
|
+
|
201
|
+
VALUE rb_big_barrett_reduce(VALUE x, VALUE m, VALUE mu, int inplace)
|
202
|
+
{
|
203
|
+
if (!NEGATIVE_P(x) && MORE(m, x))
|
204
|
+
{
|
205
|
+
return x;
|
206
|
+
}
|
207
|
+
unsigned long len = RBIGNUM_LEN(m); /* >= 1 */
|
208
|
+
if (FIXNUM_P(x))
|
209
|
+
{
|
210
|
+
return FIX2LONG(x) >= 0 ? x : rb_big_plus(m, x);
|
211
|
+
}
|
212
|
+
|
213
|
+
VALUE q = bigmul_high_digits(x, mu, len - 1, len - 1);
|
214
|
+
/* q is not normed */
|
215
|
+
q = rshift_digits_inplace(q, len + 1);
|
216
|
+
/* [x/m] - 3 <= q <= [x/m] */
|
217
|
+
q = bigmul_low_digits(q, m, len + 1);
|
218
|
+
/* q is normed */
|
219
|
+
|
220
|
+
VALUE a = inplace ? x : rb_big_clone(x);
|
221
|
+
if (RBIGNUM_LEN(a) > (long)len + 1)
|
222
|
+
{
|
223
|
+
RBIGNUM_SET_LEN(a, len + 1);
|
224
|
+
}
|
225
|
+
|
226
|
+
a = rb_big_minus(a, q);
|
227
|
+
if (NEGATIVE_P(a))
|
228
|
+
a = ADD(a, power_of_two((len + 1) * BITSPERDIG));
|
229
|
+
/* a = (x - q * m) mod (base ** (len + 1)) */
|
230
|
+
|
231
|
+
while (!MORE(m, a)) /* that is, m <= a */
|
232
|
+
a = SUB(a, m);
|
233
|
+
return rb_big_norm(a);
|
234
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#ifndef NUMTHEORY_REDUCE_H
|
2
|
+
#define NUMTHEORY_REDUCE_H
|
3
|
+
|
4
|
+
VALUE rb_big_barrett_reduce(VALUE,VALUE,VALUE,int);
|
5
|
+
VALUE rb_big_barrett_mu(VALUE);
|
6
|
+
|
7
|
+
BDIGIT montgomery_setup(BDIGIT);
|
8
|
+
VALUE rb_big_montgomery_reduce(VALUE,VALUE,VALUE,int);
|
9
|
+
BDIGIT small_montgomery_reduce(BDIGIT_DBL, BDIGIT, BDIGIT);
|
10
|
+
|
11
|
+
#endif
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = "ruby-numtheory"
|
3
|
+
gem.homepage = "http://github.com/lomereiter/ruby-numtheory"
|
4
|
+
gem.license = "MIT"
|
5
|
+
gem.summary = "Ruby number theory library"
|
6
|
+
gem.version = "0.0.6"
|
7
|
+
gem.platform = Gem::Platform::RUBY
|
8
|
+
|
9
|
+
gem.description = <<-EOF
|
10
|
+
The library is written as C extension and aims to provide
|
11
|
+
common number-theoretical functions such as powermod, jacobi symbol,
|
12
|
+
various multiplicative ones, etc.
|
13
|
+
EOF
|
14
|
+
|
15
|
+
gem.email = "lomereiter@gmail.com"
|
16
|
+
gem.authors = ["Artem Tarasov"]
|
17
|
+
|
18
|
+
gem.extensions = FileList["ext/numtheory/extconf.rb"]
|
19
|
+
gem.require_path = 'ext'
|
20
|
+
gem.files = `git ls-files`.split("\n")
|
21
|
+
|
22
|
+
gem.has_rdoc = true
|
23
|
+
gem.extra_rdoc_files = ["ext/numtheory/numtheory.c", "LICENSE.txt"]
|
24
|
+
end
|
metadata
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-numtheory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
version: 0.0.5
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.6
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
|
-
-
|
8
|
+
- Artem Tarasov
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
18
|
-
default_executable:
|
13
|
+
date: 2012-08-27 00:00:00 Z
|
19
14
|
dependencies: []
|
20
15
|
|
21
|
-
description: "
|
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"
|
22
17
|
email: lomereiter@gmail.com
|
23
18
|
executables: []
|
24
19
|
|
@@ -26,40 +21,52 @@ extensions:
|
|
26
21
|
- ext/numtheory/extconf.rb
|
27
22
|
extra_rdoc_files:
|
28
23
|
- ext/numtheory/numtheory.c
|
24
|
+
- LICENSE.txt
|
29
25
|
files:
|
30
|
-
-
|
26
|
+
- Gemfile
|
27
|
+
- LICENSE.txt
|
28
|
+
- README.md
|
29
|
+
- Rakefile
|
30
|
+
- ext/numtheory/Makefile
|
31
|
+
- ext/numtheory/constants.h
|
31
32
|
- ext/numtheory/extconf.rb
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
- ext/numtheory/numtheory.c
|
34
|
+
- ext/numtheory/numtheory.h
|
35
|
+
- ext/numtheory/numtheory_macros.c
|
36
|
+
- ext/numtheory/powermod.h
|
37
|
+
- ext/numtheory/primes.c
|
38
|
+
- ext/numtheory/primes.h
|
39
|
+
- ext/numtheory/queue.h
|
40
|
+
- ext/numtheory/reduce.c
|
41
|
+
- ext/numtheory/reduce.h
|
42
|
+
- ruby-numtheory.gemspec
|
43
|
+
homepage: http://github.com/lomereiter/ruby-numtheory
|
44
|
+
licenses:
|
45
|
+
- MIT
|
36
46
|
post_install_message:
|
37
47
|
rdoc_options: []
|
38
48
|
|
39
49
|
require_paths:
|
40
|
-
-
|
50
|
+
- ext
|
41
51
|
required_ruby_version: !ruby/object:Gem::Requirement
|
42
52
|
none: false
|
43
53
|
requirements:
|
44
54
|
- - ">="
|
45
55
|
- !ruby/object:Gem::Version
|
56
|
+
hash: -228771462311290448
|
46
57
|
segments:
|
47
|
-
- 1
|
48
|
-
- 9
|
49
58
|
- 0
|
50
|
-
version:
|
59
|
+
version: "0"
|
51
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
61
|
none: false
|
53
62
|
requirements:
|
54
63
|
- - ">="
|
55
64
|
- !ruby/object:Gem::Version
|
56
|
-
segments:
|
57
|
-
- 0
|
58
65
|
version: "0"
|
59
66
|
requirements: []
|
60
67
|
|
61
68
|
rubyforge_project:
|
62
|
-
rubygems_version: 1.
|
69
|
+
rubygems_version: 1.8.24
|
63
70
|
signing_key:
|
64
71
|
specification_version: 3
|
65
72
|
summary: Ruby number theory library
|