mr_prime 0.0.1
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/Rakefile +15 -0
- data/VERSION +1 -0
- data/ext/Makefile +157 -0
- data/ext/extconf.rb +5 -0
- data/ext/prime.c +115 -0
- data/lib/mr_prime/mr_prime_rb.rb +119 -0
- metadata +61 -0
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |s|
|
4
|
+
s.name = "mr_prime"
|
5
|
+
s.summary = "An Uber-fast primality testing library."
|
6
|
+
s.email = "burke@burkelibbey.org"
|
7
|
+
s.homepage = "http://github.com/rkneufeld/mr_prime"
|
8
|
+
s.description = "An Uber-fast primality testing library."
|
9
|
+
s.authors = ["Burke Libbey", "Ryan Neufeld"]
|
10
|
+
s.files = FileList["[A-Z]*", "{src,ext,lib}/**/*"]
|
11
|
+
s.extensions = ["ext/extconf.rb"]
|
12
|
+
end
|
13
|
+
rescue LoadError
|
14
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
15
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/ext/Makefile
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin10.0
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
exec_prefix = $(prefix)
|
11
|
+
prefix = $(DESTDIR)/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr
|
12
|
+
sharedstatedir = $(prefix)/com
|
13
|
+
mandir = $(DESTDIR)/usr/share/man
|
14
|
+
psdir = $(docdir)
|
15
|
+
oldincludedir = $(DESTDIR)/usr/include
|
16
|
+
localedir = $(datarootdir)/locale
|
17
|
+
bindir = $(exec_prefix)/bin
|
18
|
+
libexecdir = $(exec_prefix)/libexec
|
19
|
+
sitedir = $(DESTDIR)/Library/Ruby/Site
|
20
|
+
htmldir = $(docdir)
|
21
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
22
|
+
includedir = $(prefix)/include
|
23
|
+
infodir = $(DESTDIR)/usr/share/info
|
24
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
25
|
+
sysconfdir = $(prefix)/etc
|
26
|
+
libdir = $(exec_prefix)/lib
|
27
|
+
sbindir = $(exec_prefix)/sbin
|
28
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
29
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
30
|
+
dvidir = $(docdir)
|
31
|
+
vendordir = $(libdir)/ruby/vendor_ruby
|
32
|
+
datarootdir = $(prefix)/share
|
33
|
+
pdfdir = $(docdir)
|
34
|
+
archdir = $(rubylibdir)/$(arch)
|
35
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
36
|
+
datadir = $(datarootdir)
|
37
|
+
localstatedir = $(prefix)/var
|
38
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
39
|
+
|
40
|
+
CC = gcc
|
41
|
+
LIBRUBY = $(LIBRUBY_SO)
|
42
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
43
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
44
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)
|
45
|
+
|
46
|
+
RUBY_EXTCONF_H =
|
47
|
+
CFLAGS = -fno-common -arch i386 -arch x86_64 -g -Os -pipe -fno-common -DENABLE_DTRACE -fno-common -pipe -fno-common $(cflags)
|
48
|
+
INCFLAGS = -I. -I$(topdir) -I$(hdrdir) -I$(srcdir)
|
49
|
+
DEFS =
|
50
|
+
CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
51
|
+
CXXFLAGS = $(CFLAGS)
|
52
|
+
ldflags = -L. -arch i386 -arch x86_64
|
53
|
+
dldflags =
|
54
|
+
archflag =
|
55
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
|
56
|
+
LDSHARED = cc -arch i386 -arch x86_64 -pipe -bundle -undefined dynamic_lookup
|
57
|
+
AR = ar
|
58
|
+
EXEEXT =
|
59
|
+
|
60
|
+
RUBY_INSTALL_NAME = ruby
|
61
|
+
RUBY_SO_NAME = ruby
|
62
|
+
arch = universal-darwin10.0
|
63
|
+
sitearch = universal-darwin10.0
|
64
|
+
ruby_version = 1.8
|
65
|
+
ruby = /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
|
66
|
+
RUBY = $(ruby)
|
67
|
+
RM = rm -f
|
68
|
+
MAKEDIRS = mkdir -p
|
69
|
+
INSTALL = /usr/bin/install -c
|
70
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
71
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
72
|
+
COPY = cp
|
73
|
+
|
74
|
+
#### End of system configuration section. ####
|
75
|
+
|
76
|
+
preload =
|
77
|
+
|
78
|
+
libpath = . $(libdir)
|
79
|
+
LIBPATH = -L. -L$(libdir)
|
80
|
+
DEFFILE =
|
81
|
+
|
82
|
+
CLEANFILES = mkmf.log
|
83
|
+
DISTCLEANFILES =
|
84
|
+
|
85
|
+
extout =
|
86
|
+
extout_prefix =
|
87
|
+
target_prefix =
|
88
|
+
LOCAL_LIBS =
|
89
|
+
LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl
|
90
|
+
SRCS = prime.c
|
91
|
+
OBJS = prime.o
|
92
|
+
TARGET = better_prime
|
93
|
+
DLLIB = $(TARGET).bundle
|
94
|
+
EXTSTATIC =
|
95
|
+
STATIC_LIB =
|
96
|
+
|
97
|
+
BINDIR = $(bindir)
|
98
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
99
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
100
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
101
|
+
|
102
|
+
TARGET_SO = $(DLLIB)
|
103
|
+
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
104
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
105
|
+
|
106
|
+
all: $(DLLIB)
|
107
|
+
static: $(STATIC_LIB)
|
108
|
+
|
109
|
+
clean:
|
110
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
111
|
+
|
112
|
+
distclean: clean
|
113
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
114
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
115
|
+
|
116
|
+
realclean: distclean
|
117
|
+
install: install-so install-rb
|
118
|
+
|
119
|
+
install-so: $(RUBYARCHDIR)
|
120
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
121
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
122
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
123
|
+
install-rb: pre-install-rb install-rb-default
|
124
|
+
install-rb-default: pre-install-rb-default
|
125
|
+
pre-install-rb: Makefile
|
126
|
+
pre-install-rb-default: Makefile
|
127
|
+
$(RUBYARCHDIR):
|
128
|
+
$(MAKEDIRS) $@
|
129
|
+
|
130
|
+
site-install: site-install-so site-install-rb
|
131
|
+
site-install-so: install-so
|
132
|
+
site-install-rb: install-rb
|
133
|
+
|
134
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
135
|
+
|
136
|
+
.cc.o:
|
137
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
138
|
+
|
139
|
+
.cxx.o:
|
140
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
141
|
+
|
142
|
+
.cpp.o:
|
143
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
144
|
+
|
145
|
+
.C.o:
|
146
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
147
|
+
|
148
|
+
.c.o:
|
149
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
150
|
+
|
151
|
+
$(DLLIB): $(OBJS)
|
152
|
+
@-$(RM) $@
|
153
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
$(OBJS): ruby.h defines.h
|
data/ext/extconf.rb
ADDED
data/ext/prime.c
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
#include <stdbool.h>
|
2
|
+
|
3
|
+
#include "ruby.h"
|
4
|
+
|
5
|
+
typedef unsigned long long ullong;
|
6
|
+
|
7
|
+
ullong
|
8
|
+
expmod(ullong base, ullong exponent, ullong modulus)
|
9
|
+
{
|
10
|
+
ullong result = 1;
|
11
|
+
while(exponent > 0) {
|
12
|
+
if ((exponent & 1) == 1) {
|
13
|
+
result = (result * base) % modulus;
|
14
|
+
}
|
15
|
+
exponent >>= 1;
|
16
|
+
base = (base * base) % modulus;
|
17
|
+
}
|
18
|
+
return result;
|
19
|
+
}
|
20
|
+
|
21
|
+
VALUE
|
22
|
+
mrprime(VALUE obj)
|
23
|
+
{
|
24
|
+
rb_require("mr_prime/mr_prime_rb");
|
25
|
+
VALUE mrprime = rb_define_class("MR_Prime", rb_cObject);
|
26
|
+
return rb_funcall(mrprime, rb_intern("[]"), 1, obj);
|
27
|
+
}
|
28
|
+
|
29
|
+
/* Miller-Rabin algorithm to determine primality of a number.
|
30
|
+
* Uses values for a that guarantee correct results up to 314T.
|
31
|
+
* Above that, uses ryan@ryanneufeld.ca's Mr.Prime.
|
32
|
+
*/
|
33
|
+
VALUE
|
34
|
+
integer_is_prime(VALUE self)
|
35
|
+
{
|
36
|
+
if (!FIXNUM_P(self)) {
|
37
|
+
return mrprime(self);
|
38
|
+
}
|
39
|
+
|
40
|
+
ullong n = NUM2ULL(self);
|
41
|
+
|
42
|
+
int *primes;
|
43
|
+
int nprimes;
|
44
|
+
int k, i, j;
|
45
|
+
ullong m, b;
|
46
|
+
bool prime;
|
47
|
+
|
48
|
+
static int primes_1[] = {2, 3};
|
49
|
+
static int primes_2[] = {31, 73};
|
50
|
+
static int primes_3[] = {2, 7, 61};
|
51
|
+
static int primes_4[] = {2, 3, 5, 7, 11};
|
52
|
+
static int primes_5[] = {2, 3, 5, 7, 11, 13};
|
53
|
+
static int primes_6[] = {2, 3, 5, 7, 11, 13, 17};
|
54
|
+
|
55
|
+
if (n < 2) {
|
56
|
+
return Qfalse;
|
57
|
+
} else if (n < 4) {
|
58
|
+
return Qtrue;
|
59
|
+
} else if (n < 1373653) {
|
60
|
+
primes = primes_1;
|
61
|
+
nprimes = 2;
|
62
|
+
} else if (n < 9080191) {
|
63
|
+
primes = primes_2;
|
64
|
+
nprimes = 2;
|
65
|
+
} else if (n < 4759123141ULL) {
|
66
|
+
primes = primes_3;
|
67
|
+
nprimes = 3;
|
68
|
+
} else if (n < 2152302989747ULL) {
|
69
|
+
primes = primes_4;
|
70
|
+
nprimes = 5;
|
71
|
+
} else if (n < 3474749660383ULL) {
|
72
|
+
primes = primes_5;
|
73
|
+
nprimes = 6;
|
74
|
+
} else if (n < 341550071728321ULL) {
|
75
|
+
primes = primes_6;
|
76
|
+
nprimes = 7;
|
77
|
+
} else {
|
78
|
+
// Quick, do something sensible!
|
79
|
+
return mrprime(self);
|
80
|
+
}
|
81
|
+
|
82
|
+
k = 0;
|
83
|
+
m = n - 1;
|
84
|
+
while (m & 1) {
|
85
|
+
m >>= 1;
|
86
|
+
k += 1;
|
87
|
+
}
|
88
|
+
|
89
|
+
for (i = 0; i < nprimes; i++) {
|
90
|
+
b = expmod(primes[i], m, n);
|
91
|
+
|
92
|
+
if (b != 1) {
|
93
|
+
prime = false;
|
94
|
+
for (j = 0; j < k; j++) {
|
95
|
+
if (b == n - 1) {
|
96
|
+
prime = true;
|
97
|
+
break;
|
98
|
+
}
|
99
|
+
b = expmod(b, 2, n);
|
100
|
+
}
|
101
|
+
if (!prime) {
|
102
|
+
return Qfalse;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
return Qtrue;
|
108
|
+
}
|
109
|
+
|
110
|
+
void
|
111
|
+
Init_mr_prime()
|
112
|
+
{
|
113
|
+
VALUE cNumeric = rb_define_class("Numeric", rb_cObject);
|
114
|
+
rb_define_method(cNumeric, "prime?", integer_is_prime, 0);
|
115
|
+
}
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Thanks Bruce Schneier for this gem
|
2
|
+
def exponent_mod(base,exponent,modulus)
|
3
|
+
result = 1;
|
4
|
+
while(exponent > 0)
|
5
|
+
if ((exponent & 1) == 1)
|
6
|
+
result = (result * base) % modulus;
|
7
|
+
end
|
8
|
+
exponent >>= 1;
|
9
|
+
base = (base * base) % modulus;
|
10
|
+
end
|
11
|
+
|
12
|
+
return result;
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Test r&s can reconstitute n properly
|
17
|
+
class MR_Prime
|
18
|
+
attr_accessor :number
|
19
|
+
attr_reader :r,:s,:trials
|
20
|
+
|
21
|
+
# Allow for easier access to instance of class via MR_Prime[n]
|
22
|
+
def self.[](n,opts={})
|
23
|
+
MR_Prime.new(n,opts).prime?
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.trials_for_precision(prec)
|
27
|
+
k = 1
|
28
|
+
while( 1.0 / (4.0 ** k) > prec)
|
29
|
+
k += 1
|
30
|
+
end
|
31
|
+
return k
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(n,opts={})
|
35
|
+
self.number = n
|
36
|
+
set_trials(opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
def witnessed_by?(a)
|
40
|
+
result = exponent_mod(a,@s,@number)
|
41
|
+
if result == 1
|
42
|
+
return true
|
43
|
+
else
|
44
|
+
0.upto(@r-1) do |j|
|
45
|
+
result = exponent_mod(a,(2**j)*@s,@number)
|
46
|
+
if result == -1 or result == @number - 1
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
|
54
|
+
def number=(n)
|
55
|
+
@number = n
|
56
|
+
resolve_r_and_s
|
57
|
+
end
|
58
|
+
|
59
|
+
def prime?
|
60
|
+
witnesses.all? { |a| witnessed_by? a }
|
61
|
+
end
|
62
|
+
|
63
|
+
#private
|
64
|
+
|
65
|
+
# Set the number of trials to the max of num required for precision, witnesses opt, or 19 (giving at max 1.0e-10 chance of failure)
|
66
|
+
def set_trials(opts)
|
67
|
+
trials = [19] # default precision of 0.00000000036% chance of failure
|
68
|
+
if opts[:precision]
|
69
|
+
if opts[:precision] == 0 # Short circuit of absolute precision is required
|
70
|
+
@absolute = true
|
71
|
+
@trials = -1
|
72
|
+
return
|
73
|
+
else
|
74
|
+
trials.push(MR_Prime.trials_for_precision(opts[:precision]))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
trials.push(opts[:witnesses]) if opts[:witnesses]
|
78
|
+
@trials = trials.max
|
79
|
+
end
|
80
|
+
|
81
|
+
# Find R and S such that 2^r * s + 1 == @number (as per MR def'n)
|
82
|
+
def resolve_r_and_s
|
83
|
+
@r,@s=0,@number-1
|
84
|
+
while(@s.even?)
|
85
|
+
@r += 1
|
86
|
+
@s /= 2
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Witnesses require for absoulte certainty for any number < key
|
91
|
+
# OR
|
92
|
+
# the number of trials specified by :witnesses or :precision arguments
|
93
|
+
# Source Wikipedia and "The Primes Page"
|
94
|
+
def witnesses
|
95
|
+
witnesses = []
|
96
|
+
if @number < 1_373_653
|
97
|
+
witnesses = [2,3]
|
98
|
+
elsif @number < 9_080_191
|
99
|
+
witnesses = [31,73]
|
100
|
+
elsif @number < 4_759_123_141
|
101
|
+
witnesses = [2,7,61]
|
102
|
+
elsif @number < 2_152_302_898_747
|
103
|
+
witnesses = [2,3,5,7,11]
|
104
|
+
elsif @number < 3_474_749_660_383
|
105
|
+
witnesses = [2, 3, 5, 7, 11, 13]
|
106
|
+
elsif @number < 341_550_071_728_321
|
107
|
+
witnesses = [2, 3, 5, 7, 11, 13, 17]
|
108
|
+
elsif @precision
|
109
|
+
witnesses = (2...@number)
|
110
|
+
else
|
111
|
+
witnesses = Array.new(@trials).map { rand(@number-1)+1 }
|
112
|
+
end
|
113
|
+
return witnesses
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
if __FILE__ == $0 and !ARGV.empty?
|
118
|
+
puts MR_Prime[ARGV.shift.to_i]
|
119
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mr_prime
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Burke Libbey
|
8
|
+
- Ryan Neufeld
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-12-07 00:00:00 -06:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: An Uber-fast primality testing library.
|
18
|
+
email: burke@burkelibbey.org
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions:
|
22
|
+
- ext/extconf.rb
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- Rakefile
|
27
|
+
- VERSION
|
28
|
+
- ext/Makefile
|
29
|
+
- ext/extconf.rb
|
30
|
+
- ext/prime.c
|
31
|
+
- lib/mr_prime/mr_prime_rb.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/rkneufeld/mr_prime
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.3.5
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: An Uber-fast primality testing library.
|
60
|
+
test_files: []
|
61
|
+
|