congruence_solver 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.gitmodules +3 -2
- data/Gemfile +4 -0
- data/README.md +17 -10
- data/Rakefile +59 -25
- data/bench/bench_tools.rb +26 -26
- data/bench/solve_congruence_bm.rb +35 -35
- data/bin/csolve.rb +21 -21
- data/congruence_solver.gemspec +6 -6
- data/ext/congruence_solver/arith_utils.c +72 -75
- data/ext/congruence_solver/congruence_solver.c +43 -43
- data/ext/congruence_solver/congruences.c +175 -147
- data/ext/congruence_solver/extconf.rb +0 -13
- data/ext/congruence_solver/prime_gen.c +83 -83
- data/ext/congruence_solver/test/arith_utils_test.h +7 -7
- data/ext/congruence_solver/test/congruences_test.c +2 -2
- data/ext/congruence_solver/test/congruences_test.h +36 -1
- data/lib/congruence_solver/version.rb +1 -1
- data/lib/polynomial_interpreter.rb +114 -114
- data/spec/congruence_solver_spec.rb +34 -34
- data/spec/csolve_spec.rb +74 -74
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0efc553f7421a673f9a66fcb7b3b0940f7f2f82
|
4
|
+
data.tar.gz: 0146a9f00b2bf9f1ec49ae9180f4b82b817e3bf5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb9842feb8b1d72d26cfc1b6efbf86dcc357ee1a1c070dedcf6498c6a1c0c33f2cf96a5a9a0db5a224da1a74d751de3d8018dabf5bc9f67ce98126c672ee5e98
|
7
|
+
data.tar.gz: 3c3bae47bde1f4d7d5cdd91b157b6a4b3e345859af280db80a5a311bf503577d56b70b7fa2a38829a909bb1e4f0dba93bad284c257a6cfb6b980cbd8c97220b6
|
data/.gitignore
CHANGED
data/.gitmodules
CHANGED
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -2,25 +2,34 @@
|
|
2
2
|
|
3
3
|
CongruenceSolver is a gem for solving polynomial congruences. Should you ever need to solve polynomial congruences and have Ruby installed, this is the gem for you!
|
4
4
|
|
5
|
+
## Polynomial Congruences
|
6
|
+
|
7
|
+
Polynomial congruences are the central topic of most elementary number theory and abstract algebra curricula. Similar to an equation, a [congruence](https://en.wikipedia.org/wiki/Modular_equation) is an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation) arising from [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic) (also knowsn as "clock arithmetic"). For example, the idea "5 hours past 8 is 1" is expressed in the congruence ```8 + 5 = 1 mod 12```. A polynomial congruence is simply a congruence involving a polynomial, like ```x + 5 = 1 mod 12```. The problem of solving a congruence is to find all inputs satisfying the congruence, much like solving an equation (in this case, ```x = 8```). Generally speaking, congruences become more difficult to solve as the degree of the polynomial and the modulus grow. Elementary number theory develops tools like [Hensel Lifting](https://en.wikipedia.org/wiki/Hensel%27s_lemma#Hensel_Lifting) for solving polynomial congruences and the [Chinese Remainder Theorem](https://en.wikipedia.org/wiki/Chinese_remainder_theorem) for solving systems of polynomial congruences. This gem leverages these methods as implemented in C in [congruence_solver_ext](https://github.com/laneb/congruence_solver_ext).
|
8
|
+
|
5
9
|
## Installation
|
6
10
|
|
7
|
-
|
11
|
+
With [RubyGems](https://rubygems.org/) on your machine, installation is as easy as
|
12
|
+
```shell
|
13
|
+
gem install congruence_solver
|
14
|
+
```
|
15
|
+
|
16
|
+
You may also install via [bundler](http://bundler.io/), by adding this line to your application's Gemfile:
|
8
17
|
|
9
18
|
```ruby
|
10
19
|
gem 'congruence_solver'
|
11
20
|
```
|
12
21
|
|
13
|
-
|
22
|
+
and executing
|
14
23
|
|
15
|
-
|
16
|
-
|
17
|
-
|
24
|
+
```shell
|
25
|
+
$ bundle
|
26
|
+
```
|
18
27
|
|
19
|
-
|
28
|
+
in the project directory.
|
20
29
|
|
21
30
|
## Usage
|
22
31
|
|
23
|
-
To solve a polynomial congruence at the command line, simply invoke `csolve` and then enter the congruence at the prompt.
|
32
|
+
To solve a polynomial congruence at the command line, simply invoke `csolve` and then enter the congruence at the prompt.
|
24
33
|
|
25
34
|
```
|
26
35
|
csolve
|
@@ -47,9 +56,7 @@ CongruenceSolver.solve_congruence(coeffs, mod).sort #=> [1, 8, 15, 22, 26, 29,
|
|
47
56
|
|
48
57
|
## Development
|
49
58
|
|
50
|
-
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests, or rake bench to run the benchmark.
|
51
|
-
|
52
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
59
|
+
After checking out the repo, run `bundle install` to install dependencies and `bundle exec rake update_ext` to pull and compile the extension. Then, run `bundle exec rake spec` to run the tests, or `bundle exec rake bench` to run the benchmark. To build and install this gem onto your local machine, run `bundle exec rake install`.
|
53
60
|
|
54
61
|
## Contributing
|
55
62
|
|
data/Rakefile
CHANGED
@@ -1,23 +1,13 @@
|
|
1
1
|
#require "bundler/gem_tasks"
|
2
2
|
require "rspec/core/rake_task"
|
3
|
-
require
|
3
|
+
require "rake/extensiontask"
|
4
|
+
require "os"
|
4
5
|
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
=begin
|
9
|
-
namespace :test do
|
10
|
-
desc "Compile and unit test C extensions"
|
11
|
-
Rspec::Core::RakeTask.new :c => :compile_c do |t|
|
12
|
-
t.rspec_opts = C_SPEC_FILE
|
13
|
-
end
|
14
|
-
end
|
15
|
-
=end
|
16
|
-
|
17
7
|
#exe runs the csolve binary
|
18
8
|
task :exe do
|
19
|
-
|
20
|
-
|
9
|
+
$LOAD_PATH << "#{Dir.pwd}/lib/"
|
10
|
+
require_relative "bin/csolve.rb"
|
21
11
|
end
|
22
12
|
|
23
13
|
#spec runs all RSpec examples
|
@@ -26,27 +16,71 @@ RSpec::Core::RakeTask.new :spec
|
|
26
16
|
#uses task template provided by rake-compiler to run the extension compilation
|
27
17
|
#workflow. Task name: compile (do not use task name: ext)
|
28
18
|
Rake::ExtensionTask.new 'congruence_solver' do |ext|
|
29
|
-
|
19
|
+
ext.lib_dir = "lib/congruence_solver"
|
30
20
|
end
|
31
21
|
|
32
22
|
task :bench do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
23
|
+
$LOAD_PATH << "#{Dir.pwd}/lib/"
|
24
|
+
Dir.foreach("bench") do |bm_file|
|
25
|
+
path = "bench/#{bm_file}"
|
26
|
+
if File.file? path and path =~ "_bm.rb^"
|
27
|
+
require_relative path
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#update submodule containing extension.
|
33
|
+
|
34
|
+
task :fetch_ext do
|
35
|
+
EXT_DIR = "ext/congruence_solver"
|
36
|
+
`git submodule update --init --remote #{EXT_DIR}`
|
40
37
|
end
|
41
38
|
|
39
|
+
|
42
40
|
#executes compile task defined above, then cleans up the tmp directory that
|
43
41
|
#rake-compiler leaves behind for some reason
|
44
|
-
task :
|
45
|
-
|
46
|
-
|
42
|
+
task :compile_ext => :compile do
|
43
|
+
if OS.windows? then
|
44
|
+
`rmdir /s /q tmp`
|
45
|
+
else
|
46
|
+
`rm -rf tmp`
|
47
|
+
end
|
47
48
|
end
|
48
49
|
|
49
50
|
|
51
|
+
task :update_ext => [:fetch_ext, :compile_ext]
|
52
|
+
|
53
|
+
|
54
|
+
task :clean do
|
55
|
+
FILES_TO_RM_ARY = %w[congruence_solver-*.gem
|
56
|
+
lib/congruence_solver/congruence_solver.so]
|
57
|
+
|
58
|
+
file_to_rm_str = FILES_TO_RM_ARY.inject("") {|file_list, file| file_list += file + " "}
|
59
|
+
|
60
|
+
if OS.windows?
|
61
|
+
`rm -f #{file_to_rm_str}`
|
62
|
+
else
|
63
|
+
`rm -f #{file_to_rm_str}`
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
task :build => [:compile_ext] do
|
69
|
+
GEMSPEC = "congruence_solver.gemspec"
|
70
|
+
`gem build #{GEMSPEC}`
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
task :install => [:clean, :build] do
|
75
|
+
dot_gem_files = Dir.entries(Dir.pwd).select {|f| f =~ /congruence_solver\-.*\.gem/}
|
76
|
+
if dot_gem_files.empty?
|
77
|
+
STDERR.puts "Failed to build gem. Exiting."
|
78
|
+
elsif dot_gem_files.length > 1
|
79
|
+
STDERR.puts "Error: conflicting .gem files in directory. Exiting."
|
80
|
+
else
|
81
|
+
`gem install #{dot_gem_files.first}`
|
82
|
+
end
|
83
|
+
end
|
50
84
|
|
51
85
|
|
52
86
|
|
data/bench/bench_tools.rb
CHANGED
@@ -1,33 +1,33 @@
|
|
1
1
|
|
2
2
|
def polynomial_to_s(coeffs)
|
3
|
-
|
4
|
-
|
3
|
+
polynomial = ""
|
4
|
+
is_first_term = true
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
coeffs.reverse.each_with_index do |coe, idx|
|
7
|
+
exp = coeffs.length - idx - 1
|
8
|
+
if coe != 0
|
9
|
+
if is_first_term
|
10
|
+
is_first_term = false
|
11
|
+
else
|
12
|
+
if coe < 0
|
13
|
+
polynomial << " - "
|
14
|
+
else
|
15
|
+
polynomial << " + "
|
16
|
+
end
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
if coe.abs > 1 or (coe.abs == 1 and exp < 2)
|
20
|
+
polynomial << coe.abs.to_s
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
if exp > 0
|
24
|
+
polynomial << "x"
|
25
|
+
if exp > 1
|
26
|
+
polynomial << "^#{exp}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
31
|
|
32
|
-
|
32
|
+
polynomial
|
33
33
|
end
|
@@ -14,58 +14,58 @@ SMALL_FACTORED_LARGE_MOD = 510510
|
|
14
14
|
|
15
15
|
|
16
16
|
def solve_congruence_brute_force(coeffs, mod)
|
17
|
-
|
17
|
+
solutions = []
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
0.upto(mod) do |x|
|
20
|
+
sum = 0
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
coeffs.each_with_index do |coe, exp|
|
23
|
+
sum = (sum + coe*x**exp) % mod
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
if sum == 0 then solutions << x end
|
27
|
+
end
|
28
28
|
|
29
|
-
|
29
|
+
solutions
|
30
30
|
end
|
31
31
|
|
32
32
|
|
33
33
|
def bm_solve_congruence(coeffs, mod)
|
34
|
-
|
34
|
+
puts "Solving #{polynomial_to_s(coeffs)} = 0 mod #{mod}"
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
rb_bf_solutions = solve_congruence_brute_force(coeffs, mod).sort
|
37
|
+
#c_bf_solutions = CongruenceSolver.brute_force(coeffs, mod).sort
|
38
|
+
c_lifting_solutions = CongruenceSolver.lift(coeffs, mod).sort
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
unless rb_bf_solutions == c_lifting_solutions #and c_bf_solutions c_lift_solutions
|
41
|
+
puts "Solutions do not match:"
|
42
|
+
puts "Ruby/force solutions #{rb_bf_solutions.inspect}"
|
43
|
+
#puts "C/force solutions #{c_bf_solutions}"
|
44
|
+
puts "C/lifting solutions: #{c_lifting_solutions.inspect}"
|
45
|
+
end
|
46
46
|
|
47
|
-
|
47
|
+
puts "Time measurements:"
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
Benchmark.bmbm do |bm|
|
50
|
+
bm.report("Ruby/force") do
|
51
|
+
solve_congruence_brute_force(coeffs, mod)
|
52
|
+
end
|
53
53
|
=begin
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
bm.report("C/force") do
|
55
|
+
CongruenceSolver.brute_force(coeffs, mod)
|
56
|
+
end
|
57
57
|
=end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
bm.report("C/lifting") do
|
59
|
+
CongruenceSolver.lift(coeffs, mod)
|
60
|
+
end
|
61
|
+
end
|
62
62
|
|
63
|
-
|
63
|
+
print "\n\n"
|
64
64
|
end
|
65
65
|
|
66
66
|
|
67
67
|
[SMALL_DEG_POLYNOMIAL_COEFFS, LARGE_DEG_POLYNOMIAL_COEFFS].each do |coeffs|
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
[SMALL_MOD, MED_MOD, LARGE_MOD, XTRA_LARGE_MOD, XTRA_LARGE_PRIME_MOD, SMALL_FACTORED_LARGE_MOD].each do |mod|
|
69
|
+
bm_solve_congruence(coeffs, mod)
|
70
|
+
end
|
71
71
|
end
|
data/bin/csolve.rb
CHANGED
@@ -7,8 +7,8 @@ SOLVE_CONGRUENCE_BENCH_FILE = "../bench/solve_congruence_bm.rb"
|
|
7
7
|
|
8
8
|
|
9
9
|
if ARGV.pop == "bench"
|
10
|
-
|
11
|
-
|
10
|
+
require_relative SOLVE_CONGRUENCE_BENCH_FILE
|
11
|
+
exit(0)
|
12
12
|
end
|
13
13
|
|
14
14
|
CONGRUENCE_FORMAT = "(lhs polynomial) = (rhs polynomial) mod (modulus)"
|
@@ -21,34 +21,34 @@ MOD_INVALID_MSG = "Mod invalid: modulus must be an integer greater than 2"
|
|
21
21
|
puts "Congruence to solve:"
|
22
22
|
|
23
23
|
begin
|
24
|
-
|
24
|
+
coeffs, mod = PolynomialInterpreter.read_congruence(STDIN.gets)
|
25
25
|
rescue ArgumentError => e
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
if(e == PolynomialInterpreter::Errors::CONGRUENCE_INVALID)
|
27
|
+
STDERR.puts CONGRUENCE_INVALID_MSG
|
28
|
+
exit(1)
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
elsif(e == PolynomialInterpreter::Errors::LHS_POLYNOMIAL_INVALID)
|
31
|
+
STDERR.puts LHS_INVALID_MSG
|
32
|
+
exit(1)
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
elsif(e == PolynomialInterpreter::Errors::RHS_POLYNOMIAL_INVALID)
|
35
|
+
STDERR.puts RHS_INVALID_MSG
|
36
|
+
exit(1)
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
elsif(e == PolynomialInterpreter::Errors::MOD_INVALID)
|
39
|
+
STDERR.puts MOD_INVALID_MSG
|
40
|
+
exit(1)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
else
|
43
|
+
raise e
|
44
|
+
end
|
45
45
|
end
|
46
46
|
|
47
47
|
solutions = CongruenceSolver.lift(coeffs, mod).sort
|
48
48
|
|
49
49
|
if solutions.empty?
|
50
|
-
|
50
|
+
puts "No solution."
|
51
51
|
else
|
52
|
-
|
53
|
-
|
52
|
+
puts "Solutions:"
|
53
|
+
solutions.each_with_index {|sol, i| puts "(#{i}) #{sol}"}
|
54
54
|
end
|
data/congruence_solver.gemspec
CHANGED
@@ -18,12 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.files = `git ls-files`.split("\n")
|
19
19
|
spec.files += `git submodule --quiet foreach pwd`.split("\n").map do |abs_dir|
|
20
20
|
abs_dir = abs_dir.gsub(/^c:/, "C:")
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
files.map {|fname| "#{dir_in_proj}/#{fname}"}
|
21
|
+
dir_in_proj = abs_dir.gsub(/^#{Dir.pwd}\/?/, "")
|
22
|
+
Dir.chdir(abs_dir) do
|
23
|
+
files = `git ls-files`.split("\n")
|
24
|
+
files.map {|fname| "#{dir_in_proj}/#{fname}"}
|
25
|
+
end
|
27
26
|
end.flatten
|
28
27
|
spec.bindir = "bin"
|
29
28
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -35,4 +34,5 @@ Gem::Specification.new do |spec|
|
|
35
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
36
35
|
spec.add_development_dependency "rspec", "~> 2.4"
|
37
36
|
spec.add_development_dependency "rake-compiler", "~>0.9"
|
37
|
+
spec.add_development_dependency "os", "~>0.9"
|
38
38
|
end
|
@@ -3,130 +3,127 @@
|
|
3
3
|
#include "prime_gen.h"
|
4
4
|
#include "arith_utils.h"
|
5
5
|
|
6
|
-
|
6
|
+
//Expects 0 <= x,y < mod
|
7
7
|
int mod_sum(int x, int y, int mod){
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
if(y >= mod - x){
|
12
|
-
return y - (mod - x);
|
13
|
-
}
|
8
|
+
if(y >= mod - x){
|
9
|
+
return y - (mod - x);
|
10
|
+
}
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
else{
|
13
|
+
return y + x;
|
14
|
+
}
|
18
15
|
}
|
19
16
|
|
20
17
|
|
21
18
|
int mod_inv(int n, int mod){
|
22
|
-
|
19
|
+
int y, a;
|
23
20
|
|
24
|
-
|
21
|
+
if(n!=0){
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
while(n<0){
|
24
|
+
n+=mod;
|
25
|
+
}
|
29
26
|
|
30
|
-
|
31
|
-
|
27
|
+
for(y = 1; y < mod; y++){
|
28
|
+
a = mod_product(y, n, mod);
|
32
29
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
if(a == 1){
|
31
|
+
return y;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
38
35
|
|
39
|
-
|
36
|
+
return 0;
|
40
37
|
}
|
41
38
|
|
42
39
|
|
43
40
|
int coprime(int n1, int n2){
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
41
|
+
//naive algorithm but efficient when n1 has already been factorized
|
42
|
+
int * n1Factors = prime_factors(n1);
|
43
|
+
int numOfFactors = *n1Factors;
|
44
|
+
int * factors = n1Factors+1;
|
45
|
+
int shareFactor = 0;
|
46
|
+
int i;
|
47
|
+
|
48
|
+
for(i=0; i<numOfFactors; i++){
|
49
|
+
if(n2 % factors[i] == 0){
|
50
|
+
shareFactor = 1;
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
free(n1Factors);
|
56
|
+
|
57
|
+
return !shareFactor;
|
61
58
|
}
|
62
59
|
|
63
60
|
|
64
61
|
int mod_product(int num1, int num2, int mod){
|
65
|
-
|
66
|
-
|
62
|
+
int prod = 0;
|
63
|
+
int i;
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
for(i = 0; i < num1; i++){
|
66
|
+
prod = mod_sum(prod, num2, mod);
|
67
|
+
}
|
71
68
|
|
72
|
-
|
69
|
+
return prod;
|
73
70
|
}
|
74
71
|
|
75
|
-
|
72
|
+
//expects 0 <= n < mod
|
76
73
|
int mod_power(int n, int power, int mod){
|
77
|
-
|
78
|
-
|
74
|
+
int product = n;
|
75
|
+
int i;
|
79
76
|
|
80
|
-
|
81
|
-
|
82
|
-
|
77
|
+
for(i = 1; i < power; i++){
|
78
|
+
product = mod_product(product, n, mod);
|
79
|
+
}
|
83
80
|
|
84
|
-
|
81
|
+
return product;
|
85
82
|
}
|
86
83
|
|
87
84
|
|
88
85
|
int totient(int n){
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
86
|
+
int * divisorList = prime_factors(n);
|
87
|
+
int listLength = divisorList[0];
|
88
|
+
int * divisors = divisorList+1;
|
89
|
+
int i;
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
91
|
+
for(i = 0; i < listLength; i++){
|
92
|
+
n *= (divisors[i] - 1);
|
93
|
+
n /= divisors[i];
|
94
|
+
}
|
98
95
|
|
99
|
-
|
96
|
+
free(divisorList);
|
100
97
|
|
101
|
-
|
98
|
+
return n;
|
102
99
|
}
|
103
100
|
|
104
101
|
|
105
102
|
|
106
103
|
|
107
104
|
int mod_eval_polynomial(int degree, int coeffs[], int mod, int x){
|
108
|
-
int
|
105
|
+
int tot = coeffs[degree];
|
109
106
|
int i;
|
110
107
|
|
111
|
-
for(i = 1; i
|
112
|
-
|
113
|
-
|
108
|
+
for(i = degree - 1; i >= 0; i--){
|
109
|
+
tot = mod_product(tot, x, mod);
|
110
|
+
tot = mod_sum(tot, coeffs[i], mod);
|
114
111
|
}
|
115
112
|
|
116
|
-
return
|
113
|
+
return tot;
|
117
114
|
}
|
118
115
|
|
119
116
|
|
120
117
|
long eval_polynomial(int degree, int coeffs[], int x){
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
long int sum = coeffs[0];
|
119
|
+
long int powx;
|
120
|
+
int i;
|
124
121
|
|
125
|
-
|
126
|
-
|
127
|
-
|
122
|
+
for(i = 1, powx = x; i <= degree; i++, powx*=x){
|
123
|
+
sum += powx*coeffs[i];
|
124
|
+
}
|
128
125
|
|
129
|
-
|
126
|
+
return sum;
|
130
127
|
}
|
131
128
|
|
132
129
|
|