better_prime 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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/better_prime/mr_prime.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 = "better_prime"
|
5
|
+
s.summary = "An Uber-fast primality testing library."
|
6
|
+
s.email = "burke@burkelibbey.org"
|
7
|
+
s.homepage = "http://github.com/burke/better_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("better_prime/mr_prime");
|
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_better_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: better_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/better_prime/mr_prime.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/burke/better_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
|
+
|