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 ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "rake", ">= 0.9"
5
+ gem "rspec", "~> 2.10.0"
6
+ gem "bundler", ">= 1.0.0"
7
+ gem "rake-compiler"
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Artem Tarasov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # ruby-numtheory
2
+
3
+ The library is written as C extension and aims to provide fast implementations of common number-theoretical algorithms.
4
+
5
+ ## Currently implemented
6
+
7
+ * powermod (uses sliding window exponentiation)
8
+ * miller-rabin test for primality
9
+ * standard BPSW primality test
10
+ * eratosthenes sieve
11
+ * factorization (via trial division)
12
+ * factorial (uses PrimeSwing algorithm)
13
+ * sigma (σ)
14
+ * moebius (μ)
15
+ * eulerphi (φ)
16
+ * primepi (π)
17
+ * fibonacci
18
+ * modular inverse
19
+ * extended gcd
20
+ * primitive pythagorean triple generator
21
+ * integer square root
22
+ * square root in Z/pZ (for prime p)
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ spec = Gem::Specification.load('ruby-numtheory.gemspec')
15
+
16
+ require 'rspec/core'
17
+ require 'rspec/core/rake_task'
18
+ RSpec::Core::RakeTask.new(:spec) do |spec|
19
+ spec.pattern = FileList["spec/**/*_spec.rb"]
20
+ end
21
+
22
+ task :test => :spec
23
+ task :default => :test
24
+
25
+ require 'rubygems/package_task'
26
+ Gem::PackageTask.new(spec) do |pkg|
27
+ end
28
+
29
+ task :build => :gem
30
+
31
+ require 'rake/extensiontask'
32
+ Rake::ExtensionTask.new('numtheory', spec) do |ext|
33
+ ext.cross_compile = true
34
+ end
@@ -0,0 +1,187 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ #### Start of system configuration section. ####
5
+
6
+ srcdir = .
7
+ topdir = /usr/local/include/ruby-1.9.1
8
+ hdrdir = /usr/local/include/ruby-1.9.1
9
+ arch_hdrdir = /usr/local/include/ruby-1.9.1/$(arch)
10
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
11
+ prefix = $(DESTDIR)/usr/local
12
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
13
+ exec_prefix = $(prefix)
14
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
15
+ sitehdrdir = $(rubyhdrdir)/site_ruby
16
+ rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
17
+ vendordir = $(rubylibprefix)/vendor_ruby
18
+ sitedir = $(rubylibprefix)/site_ruby
19
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
20
+ mandir = $(datarootdir)/man
21
+ localedir = $(datarootdir)/locale
22
+ libdir = $(exec_prefix)/lib
23
+ psdir = $(docdir)
24
+ pdfdir = $(docdir)
25
+ dvidir = $(docdir)
26
+ htmldir = $(docdir)
27
+ infodir = $(datarootdir)/info
28
+ docdir = $(datarootdir)/doc/$(PACKAGE)
29
+ oldincludedir = $(DESTDIR)/usr/include
30
+ includedir = $(prefix)/include
31
+ localstatedir = $(prefix)/var
32
+ sharedstatedir = $(prefix)/com
33
+ sysconfdir = $(prefix)/etc
34
+ datadir = $(datarootdir)
35
+ datarootdir = $(prefix)/share
36
+ libexecdir = $(exec_prefix)/libexec
37
+ sbindir = $(exec_prefix)/sbin
38
+ bindir = $(exec_prefix)/bin
39
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
40
+ archdir = $(rubylibdir)/$(arch)
41
+ sitelibdir = $(sitedir)/$(ruby_version)
42
+ sitearchdir = $(sitelibdir)/$(sitearch)
43
+ vendorlibdir = $(vendordir)/$(ruby_version)
44
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
45
+
46
+ CC = gcc
47
+ CXX = g++
48
+ LIBRUBY = $(LIBRUBY_A)
49
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
50
+ LIBRUBYARG_SHARED = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)
51
+ LIBRUBYARG_STATIC = -Wl,-R -Wl,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static
52
+ OUTFLAG = -o
53
+ COUTFLAG = -o
54
+
55
+ RUBY_EXTCONF_H =
56
+ cflags = $(optflags) $(debugflags) $(warnflags)
57
+ optflags = -O3
58
+ debugflags = -ggdb
59
+ warnflags = -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long
60
+ CFLAGS = -fPIC $(cflags)
61
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
62
+ DEFS = -D_FILE_OFFSET_BITS=64
63
+ CPPFLAGS = $(DEFS) $(cppflags)
64
+ CXXFLAGS = $(CFLAGS) $(cxxflags)
65
+ ldflags = -L. -rdynamic -Wl,-export-dynamic
66
+ dldflags =
67
+ ARCH_FLAG =
68
+ DLDFLAGS = $(ldflags) $(dldflags)
69
+ LDSHARED = $(CC) -shared
70
+ LDSHAREDXX = $(CXX) -shared
71
+ AR = ar
72
+ EXEEXT =
73
+
74
+ RUBY_BASE_NAME = ruby
75
+ RUBY_INSTALL_NAME = ruby
76
+ RUBY_SO_NAME = ruby
77
+ arch = i686-linux
78
+ sitearch = $(arch)
79
+ ruby_version = 1.9.1
80
+ ruby = /usr/local/bin/ruby
81
+ RUBY = $(ruby)
82
+ RM = rm -f
83
+ RM_RF = $(RUBY) -run -e rm -- -rf
84
+ RMDIRS = $(RUBY) -run -e rmdir -- -p
85
+ MAKEDIRS = /bin/mkdir -p
86
+ INSTALL = /usr/bin/install -c
87
+ INSTALL_PROG = $(INSTALL) -m 0755
88
+ INSTALL_DATA = $(INSTALL) -m 644
89
+ COPY = cp
90
+
91
+ #### End of system configuration section. ####
92
+
93
+ preload =
94
+
95
+ libpath = . $(libdir)
96
+ LIBPATH = -L. -L$(libdir) -Wl,-R$(libdir)
97
+ DEFFILE =
98
+
99
+ CLEANFILES = mkmf.log
100
+ DISTCLEANFILES =
101
+ DISTCLEANDIRS =
102
+
103
+ extout =
104
+ extout_prefix =
105
+ target_prefix =
106
+ LOCAL_LIBS =
107
+ LIBS = -lpthread -lrt -ldl -lcrypt -lm -lc
108
+ SRCS = numtheory_macros.c primes.c queue.c reduce.c numtheory.c
109
+ OBJS = numtheory_macros.o primes.o queue.o reduce.o numtheory.o
110
+ TARGET = numtheory
111
+ DLLIB = $(TARGET).so
112
+ EXTSTATIC =
113
+ STATIC_LIB =
114
+
115
+ BINDIR = $(bindir)
116
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
117
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
118
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
119
+ HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
120
+ ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
121
+
122
+ TARGET_SO = $(DLLIB)
123
+ CLEANLIBS = $(TARGET).so
124
+ CLEANOBJS = *.o *.bak
125
+
126
+ all: $(DLLIB)
127
+ static: $(STATIC_LIB)
128
+ .PHONY: all install static install-so install-rb
129
+ .PHONY: clean clean-so clean-rb
130
+
131
+ clean-rb-default::
132
+ clean-rb::
133
+ clean-so::
134
+ clean: clean-so clean-rb-default clean-rb
135
+ @-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
136
+
137
+ distclean-rb-default::
138
+ distclean-rb::
139
+ distclean-so::
140
+ distclean: clean distclean-so distclean-rb-default distclean-rb
141
+ @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
142
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
143
+ @-$(RMDIRS) $(DISTCLEANDIRS)
144
+
145
+ realclean: distclean
146
+ install: install-so install-rb
147
+
148
+ install-so: $(RUBYARCHDIR)
149
+ install-so: $(RUBYARCHDIR)/$(DLLIB)
150
+ $(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
151
+ @-$(MAKEDIRS) $(@D)
152
+ $(INSTALL_PROG) $(DLLIB) $(@D)
153
+ install-rb: pre-install-rb install-rb-default
154
+ install-rb-default: pre-install-rb-default
155
+ pre-install-rb: Makefile
156
+ pre-install-rb-default: Makefile
157
+ $(RUBYARCHDIR):
158
+ $(MAKEDIRS) $@
159
+
160
+ site-install: site-install-so site-install-rb
161
+ site-install-so: install-so
162
+ site-install-rb: install-rb
163
+
164
+ .SUFFIXES: .c .m .cc .cxx .cpp .C .o
165
+
166
+ .cc.o:
167
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
168
+
169
+ .cxx.o:
170
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
171
+
172
+ .cpp.o:
173
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
174
+
175
+ .C.o:
176
+ $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
177
+
178
+ .c.o:
179
+ $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
180
+
181
+ $(DLLIB): $(OBJS) Makefile
182
+ @-$(RM) $(@)
183
+ $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
184
+
185
+
186
+
187
+ $(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
@@ -0,0 +1,24 @@
1
+ unsigned long long numtheory_small_factorials[] =
2
+ { 1ULL, 1ULL, 2ULL, 6ULL, 24ULL, 120ULL, 720ULL, 5040ULL, 40320ULL,
3
+ 362880ULL, 3628800ULL, 39916800ULL, 479001600ULL, 6227020800ULL,
4
+ 87178291200ULL, 1307674368000ULL, 20922789888000ULL, 355687428096000ULL,
5
+ 6402373705728000ULL, 121645100408832000ULL, 2432902008176640000ULL };
6
+
7
+ unsigned long long numtheory_small_odd_swings[] =
8
+ { 1ULL, 1ULL, 1ULL, 3ULL, 3ULL, 15ULL, 5ULL, 35ULL, 35ULL, 315ULL, 63ULL,
9
+ 693ULL, 231ULL, 3003ULL, 429ULL, 6435ULL, 6435ULL, 109395ULL, 12155ULL,
10
+ 230945ULL, 46189ULL, 969969ULL, 88179ULL, 2028117ULL, 676039ULL, 16900975ULL,
11
+ 1300075ULL, 35102025ULL, 5014575ULL, 145422675ULL, 9694845ULL, 300540195ULL,
12
+ 300540195ULL, 9917826435ULL, 583401555ULL, 20419054425ULL, 2268783825ULL,
13
+ 83945001525ULL, 4418157975ULL, 172308161025ULL, 34461632205ULL,
14
+ 1412926920405ULL, 67282234305ULL, 2893136075115ULL, 263012370465ULL,
15
+ 11835556670925ULL, 514589420475ULL, 24185702762325ULL, 8061900920775ULL,
16
+ 395033145117975ULL, 15801325804719ULL, 805867616040669ULL, 61989816618513ULL,
17
+ 3285460280781189ULL, 121683714103007ULL, 6692604275665385ULL,
18
+ 956086325095055ULL, 54496920530418135ULL, 1879204156221315ULL,
19
+ 110873045217057585ULL, 7391536347803839ULL, 450883717216034179ULL,
20
+ 14544636039226909ULL, 916312070471295267ULL, 916312070471295267ULL };
21
+
22
+ char issquare_mod256[] = { 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
23
+
24
+ char issquare_mod255[] = { 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -1,2 +1,3 @@
1
1
  require 'mkmf'
2
+ $CFLAGS = "-g -O3 -funroll-all-loops -fPIC -pedantic -std=c99"
2
3
  create_makefile 'numtheory'
@@ -1,58 +1,26 @@
1
- #include <ruby.h>
2
- #include <stdio.h>
3
- #include <math.h>
1
+ #include "numtheory.h"
4
2
 
5
3
  #include "primes.h"
6
4
  #include "queue.h"
5
+ #include "reduce.h"
7
6
  #include "numtheory_macros.c"
8
7
  #include "constants.h"
9
8
 
10
- static VALUE numtheory_powermod(int argc, VALUE *argv);
11
- static VALUE numtheory_int_powermod(VALUE b, VALUE p, VALUE m);
12
- static VALUE numtheory_miller_rabin_pseudoprime_p(VALUE n);
13
- static VALUE numtheory_nextprime(VALUE n);
14
- static VALUE numtheory_precompute_primes_upto(VALUE obj, VALUE n);
15
- static VALUE numtheory_prime(VALUE obj, VALUE i);
16
- static VALUE numtheory_prime_p(VALUE n);
17
- static VALUE numtheory_primepi(VALUE obj, VALUE n);
18
- static VALUE numtheory_fibonacci(int argc, VALUE *argv);
19
- static VALUE numtheory_sigma(int argc, VALUE *argv);
20
- static VALUE numtheory_eulerphi(VALUE obj, VALUE n);
21
- static VALUE numtheory_moebius(VALUE obj, VALUE n);
22
- static VALUE numtheory_prime_division(VALUE n);
23
- static VALUE numtheory_product(VALUE obj, VALUE arr);
24
- static VALUE numtheory_primes_upto(VALUE min, VALUE max);
25
- static VALUE numtheory_factorial_primeswing(VALUE n);
26
- static VALUE numtheory_extended_gcd(VALUE x, VALUE y);
27
- static VALUE numtheory_modular_inverse(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_jacobi(VALUE a, VALUE n);
33
- static VALUE numtheory_sqrtmod(VALUE a, VALUE p);
34
- static VALUE numtheory_isqrt(VALUE n);
35
- static VALUE numtheory_perfect_square_p(VALUE n);
36
- static VALUE numtheory_bpsw_pseudoprime_p(VALUE n);
37
-
38
9
  static VALUE mNumTheory;
39
10
  static ID primality_tests_ID;
40
11
 
41
- static ID id_rand, id_mod, id_divmod,
42
- id_gcd, id_lcm, id_pow, id_mul;
43
-
44
12
  static unsigned long PRIMES_UPPER_LIMIT = 3141592;
45
13
  static unsigned long NUM_OF_PRIMES;
46
14
 
47
- static const VALUE zero = INT2FIX(0);
48
- static const VALUE one = INT2FIX(1);
49
- static const VALUE two = INT2FIX(2);
50
- static const VALUE three = INT2FIX(3);
51
- static const VALUE four = INT2FIX(4);
52
- static const VALUE five = INT2FIX(5);
53
- static const VALUE six = INT2FIX(6);
54
- static const VALUE seven = INT2FIX(7);
55
- static const VALUE eight = INT2FIX(8);
15
+ const VALUE zero = INT2FIX(0);
16
+ const VALUE one = INT2FIX(1);
17
+ const VALUE two = INT2FIX(2);
18
+ const VALUE three = INT2FIX(3);
19
+ const VALUE four = INT2FIX(4);
20
+ const VALUE five = INT2FIX(5);
21
+ const VALUE six = INT2FIX(6);
22
+ const VALUE seven = INT2FIX(7);
23
+ const VALUE eight = INT2FIX(8);
56
24
 
57
25
  /*
58
26
  * The <code>NumTheory</code> module contains basic number-theoretical
@@ -71,6 +39,7 @@ Init_numtheory()
71
39
 
72
40
  id_rand = rb_intern("rand");
73
41
  id_mod = rb_intern("modulo");
42
+ id_div = rb_intern("div");
74
43
  id_divmod = rb_intern("divmod");
75
44
  id_gcd = rb_intern("gcd");
76
45
  id_lcm = rb_intern("lcm");
@@ -180,150 +149,6 @@ numtheory_precompute_primes_upto(VALUE obj, VALUE n)
180
149
  return Qnil;
181
150
  }
182
151
 
183
-
184
- inline static VALUE TO_BIGNUM(VALUE x) {
185
- return FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x;
186
- }
187
-
188
- inline static unsigned long TO_ULONG(VALUE x) {
189
- if (!FIXNUM_P(x))
190
- {
191
- if (rb_big_cmp(x, ULONG2NUM(ULONG_MAX)) != one)
192
- return rb_big2ulong(x);
193
- else
194
- rb_raise(rb_eNotImpError, "Not implemented for numbers >= 2**32");
195
- }
196
- return FIX2ULONG(x);
197
- }
198
-
199
- inline static int EVEN_P(VALUE x) {
200
- return FIXNUM_P(x) ? !(FIX2ULONG(x)&1) : !(RBIGNUM_DIGITS(x)[0]&1);
201
- }
202
-
203
- inline static int ZERO_P(VALUE x) {
204
- return FIXNUM_P(x) ? FIX2LONG(x) == 0 : rb_bigzero_p(x);
205
- }
206
-
207
- inline static VALUE ADD(VALUE x, VALUE y) {
208
- return FIXNUM_P(x) ? FIXNUM_P(y) ?
209
- LONG2NUM(FIX2LONG(x) + FIX2LONG(y)) :
210
- rb_big_plus(y, x) :
211
- rb_big_plus(x, y);
212
- }
213
-
214
- inline static VALUE SUB(VALUE x, VALUE y) {
215
- return (FIXNUM_P(x) && FIXNUM_P(y)) ?
216
- LONG2NUM(FIX2LONG(x) - FIX2LONG(y)) :
217
- rb_big_minus(TO_BIGNUM(x), y);
218
- }
219
-
220
- #define NEGATE(x) do { if (FIXNUM_P(x)) x = -x; \
221
- else RBIGNUM_SET_SIGN(x, !RBIGNUM_SIGN(x)); } \
222
- while(0);
223
-
224
- inline static VALUE MUL(VALUE x, VALUE y) {
225
- return rb_funcall(x, id_mul, 1, y);
226
- }
227
-
228
- inline static VALUE POW(VALUE b, VALUE p) {
229
- return rb_funcall(b, id_pow, 1, p);
230
- }
231
-
232
- inline static VALUE DIV(VALUE x, VALUE y) {
233
- if (ZERO_P(y))
234
- {
235
- rb_raise(rb_eZeroDivError, "divided by 0");
236
- }
237
- return FIXNUM_P(x) ? FIXNUM_P(y) ?
238
- INT2FIX( FIX2LONG(x) / FIX2LONG(y)) :
239
- zero :
240
- rb_big_div(x, y);
241
- }
242
-
243
- inline static VALUE DIVMOD(VALUE x, VALUE y) {
244
- return rb_funcall(x, id_divmod, 1, y);
245
- }
246
-
247
- inline static VALUE MOD(VALUE x, VALUE y) {
248
- return rb_funcall(x, id_mod, 1, y);
249
- }
250
-
251
- inline static int MOD_4(VALUE x) {
252
- return FIXNUM_P(x) ? FIX2LONG(x) & 3 :
253
- RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 3 :
254
- 4 - RBIGNUM_DIGITS(x)[0] & 3;
255
- }
256
-
257
- inline static int MOD_8(VALUE x) {
258
- return FIXNUM_P(x) ? FIX2LONG(x) & 7 :
259
- RBIGNUM_SIGN(x) ? RBIGNUM_DIGITS(x)[0] & 7 :
260
- 8 - RBIGNUM_DIGITS(x)[0] & 7;
261
- }
262
-
263
- inline static int EQL(VALUE x, VALUE y) {
264
- return (FIXNUM_P(x) && FIXNUM_P(y)) ?
265
- x == y :
266
- rb_big_eq(TO_BIGNUM(x), y) == Qtrue;
267
- }
268
-
269
- inline static int MORE(VALUE x, VALUE y) {
270
- return (FIXNUM_P(x) && FIXNUM_P(y)) ?
271
- FIX2LONG(x) > FIX2LONG(y) :
272
- rb_big_cmp(TO_BIGNUM(x), y) == one;
273
- }
274
-
275
- inline static int LESS(VALUE x, VALUE y) {
276
- return (FIXNUM_P(x) && FIXNUM_P(y)) ?
277
- FIX2LONG(x) < FIX2LONG(y) :
278
- rb_big_cmp(TO_BIGNUM(x), y) == INT2FIX(-1);
279
- }
280
-
281
- inline static int MORE_EQL(VALUE x, VALUE y) {
282
- return (FIXNUM_P(x) && FIXNUM_P(y)) ?
283
- FIX2LONG(x) >= FIX2LONG(y) :
284
- rb_big_cmp(TO_BIGNUM(x), y) != INT2FIX(-1);
285
- }
286
-
287
- inline static VALUE ABS(VALUE x) {
288
- if (FIXNUM_P(x))
289
- return INT2FIX(abs(FIX2LONG(x)));
290
- VALUE v = rb_big_clone(x);
291
- RBIGNUM_SET_SIGN(v, 1);
292
- return v;
293
- }
294
-
295
- inline static int NEGATIVE_P(VALUE x) {
296
- return FIXNUM_P(x) ? FIX2LONG(x) < 0 : RBIGNUM_NEGATIVE_P(x);
297
- }
298
-
299
- inline static VALUE CLONE(VALUE x) {
300
- return FIXNUM_P(x) ? x : rb_big_clone(x);
301
- }
302
-
303
- inline static int INTEGER_P(VALUE x) {
304
- return (TYPE(x) == T_FIXNUM) || (TYPE(x) == T_BIGNUM);
305
- }
306
-
307
- inline static VALUE DOUBLED(VALUE x) {
308
- return FIXNUM_P(x) ? LONG2NUM(FIX2LONG(x) << 1) :
309
- rb_big_lshift(x, one);
310
- }
311
-
312
- inline static VALUE HALF(VALUE x) {
313
- return FIXNUM_P(x) ? INT2FIX(FIX2LONG(x) >> 1) :
314
- rb_big_rshift(x, one);
315
- }
316
-
317
- inline static VALUE RIGHT_SHIFT(VALUE x, int s) {
318
- return FIXNUM_P(x) ? INT2FIX(FIX2LONG(x) >> s) :
319
- rb_big_rshift(x, INT2FIX(s));
320
- }
321
-
322
- #ifdef min
323
- #undef min
324
- #endif
325
- inline static int min(int a, int b) { return a < b ? a : b; }
326
-
327
152
  /*
328
153
  * call-seq:
329
154
  * NumTheory.powermod(base, power, [modulo, one]) -> obj
@@ -362,6 +187,7 @@ numtheory_powermod(int argc, VALUE *argv)
362
187
  }
363
188
 
364
189
  static VALUE int_powermod_sliding_window(VALUE,VALUE,VALUE);
190
+ static VALUE int_powermod_sliding_window_br(VALUE,VALUE,VALUE);
365
191
 
366
192
  /*
367
193
  * call-seq:
@@ -395,19 +221,30 @@ numtheory_int_powermod(VALUE b, VALUE p, VALUE m){
395
221
  {
396
222
  b = MOD(b, m);
397
223
  }
398
- if (FIXNUM_P(p) || RBIGNUM_LEN(p) < 4)
399
- {
400
- VALUE result = one;
401
- FOR_BITS(p, result = MUL(result, result),
402
- {},
403
- result = MUL(result, b),
404
- result = MOD(result, m));
405
- return result;
406
- }
407
- else
408
- {
224
+ const int SLIDING_WINDOW_THRESHOLD = 4;
225
+ const int BARRETT_REDUCE_THRESHOLD = 4;
226
+
227
+ int use_barrett = 0,
228
+ use_sliding_window = 0;
229
+
230
+ if (!FIXNUM_P(p) && RBIGNUM_LEN(p) >= SLIDING_WINDOW_THRESHOLD)
231
+ use_sliding_window = 1;
232
+
233
+ if (!FIXNUM_P(m) && RBIGNUM_LEN(m) >= BARRETT_REDUCE_THRESHOLD)
234
+ use_barrett = 1;
235
+
236
+ if (use_barrett)
237
+ return int_powermod_sliding_window_br(b, p, m);
238
+
239
+ if (use_sliding_window)
409
240
  return int_powermod_sliding_window(b, p, m);
410
- }
241
+
242
+ VALUE result = one;
243
+ FOR_BITS(p, result = MUL(result, result),
244
+ {},
245
+ result = MUL(result, b),
246
+ result = MOD(result, m));
247
+ return result;
411
248
  }
412
249
 
413
250
  static int tail_zeros(VALUE n)
@@ -1240,7 +1077,7 @@ numtheory_multiplicative_order(VALUE a, VALUE m)
1240
1077
  return result;
1241
1078
  }
1242
1079
 
1243
- inline VALUE* triple_new(VALUE v1, VALUE v2, VALUE v3)
1080
+ static inline VALUE* triple_new(VALUE v1, VALUE v2, VALUE v3)
1244
1081
  {
1245
1082
  VALUE* v = malloc(sizeof(VALUE)*3);
1246
1083
  v[0] = v1; v[1] = v2; v[2] = v3;
@@ -1327,7 +1164,7 @@ numtheory_popcount(VALUE n)
1327
1164
  return ULONG2NUM(k);
1328
1165
  }
1329
1166
 
1330
- static int
1167
+ int
1331
1168
  int_bitlength(unsigned int v)
1332
1169
  {
1333
1170
  // taken from http://graphics.stanford.edu/~seander/bithacks.html
@@ -1762,83 +1599,10 @@ numtheory_bpsw_pseudoprime_p(VALUE n)
1762
1599
  return lucas_pseudoprime_p(num, one, RIGHT_SHIFT(SUB(one, INT2FIX(d)), 2));
1763
1600
  }
1764
1601
 
1765
- static VALUE
1766
- int_powermod_sliding_window(VALUE b, VALUE p, VALUE m){
1767
- VALUE result = one;
1768
- /* used when p is bignum only */
1769
- enum { squaring, collecting } state;
1770
-
1771
- state = collecting;
1772
- int len, k;
1773
- int zeros = 0;
1774
- int pow = 0;
1775
-
1776
- /* adjusting window size */
1777
- len = RBIGNUM_LEN(p);
1778
- if (len < 8) k = 4;
1779
- else if (len < 20) k = 5;
1780
- else if (len < 48) k = 6;
1781
- else k = 7;
1782
-
1783
- len = 0;
1784
-
1785
- VALUE b_squared = MOD(MUL(b, b), m);
1786
- VALUE *powers = ALLOCA_N(VALUE, 1<<(k-1));
1787
- powers[0] = b;
1788
- int i;
1789
- /* precomputation of odd powers;
1790
- powers[n] = (b ** (2n + 1)) % m */
1791
- for (i = 1; i < (1<<(k-1)); ++i)
1792
- powers[i] = MOD(MUL(powers[i-1], b_squared), m);
1793
-
1794
- FOR_BITS(p, {},
1795
- { /* if the bit is zero */
1796
- if (state == collecting) {
1797
- ++ len;
1798
- ++ zeros;
1799
- pow <<= 1;
1800
- if (len == k) {
1801
- pow >>= zeros;
1802
-
1803
- for (i = len; i > zeros; i--)
1804
- result = MOD(MUL(result, result), m);
1805
- result = MOD(MUL(result, powers[pow>>1]), m);
1806
- while (zeros--)
1807
- result = MOD(MUL(result, result), m);
1808
-
1809
- state = squaring; pow = len = zeros = 0;
1810
- }
1811
- } else {
1812
- result = MOD(MUL(result, result), m);
1813
- }
1814
- },
1815
- { /* the bit is one */
1816
- if (state == collecting) {
1817
- ++ len;
1818
- zeros = 0;
1819
- pow = (pow << 1) + 1;
1820
- if (len == k) {
1821
- while (len--)
1822
- result = MOD(MUL(result, result), m);
1823
- result = MOD(MUL(result, powers[pow>>1]), m);
1824
- state = squaring;
1825
- pow = len = 0;
1826
- }
1827
- } else {
1828
- state = collecting;
1829
- pow = 1;
1830
- len = 1;
1831
- zeros = 0;
1832
- }
1833
- }, {});
1834
- if (len > 0) {
1835
- pow >>= zeros;
1836
-
1837
- for (i = len; i > zeros; i--)
1838
- result = MOD(MUL(result, result), m);
1839
- result = MOD(MUL(result, powers[pow>>1]), m);
1840
- while (zeros--)
1841
- result = MOD(MUL(result, result), m);
1842
- }
1843
- return result;
1844
- }
1602
+ DEFINE_POWERMOD_SLIDING_WINDOW(int_powermod_sliding_window,
1603
+ {},
1604
+ MOD)
1605
+
1606
+ DEFINE_POWERMOD_SLIDING_WINDOW(int_powermod_sliding_window_br,
1607
+ VALUE mu = rb_big_barrett_mu(m),
1608
+ BARRETT_MOD)