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.
- 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
|