congruence_solver 0.3.0 → 0.3.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.
- 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
|
|