Building Abstractions with Functions - Functions and the Processes They Generate - Example: Testing for Primality - Probabilistic methods - exponentials, module
Structure and Interpretation of Computer Programs: JavaScript Edition(Harold Abelson(著)、Gerald Jay Sussman(著)、Julie Sussman(著)、The MIT Press)のChapter 1(Building Abstractions with Functions)、1.2(Functions and the Processes They Generate)、1.2.6(Example: Testing for Primality)、Probabilistic methods、Exercise 1.25の解答を求めてみる。
Shi is not correct.
exponentialsを求めてから剰余を計算することになるから、元の方法と比べて大きな整数の剰余を計算することになる。
実際に確認。
コード
function square(x) {
return x * x;
}
function is_even(n) {
return n % 2 === 0;
}
function display(x) {
console.log(x);
}
function get_time() {
// return Date.now();
return performance.now();
}
function math_floor(x) {
return Math.floor(x);
}
function math_random() {
return Math.random();
}
function fast_expt(b, n) {
return n === 0 ?
1 :
is_even(n) ?
square(fast_expt(b, n / 2)) :
b * fast_expt(b, n - 1);
}
function expmod(base, exp, m) {
return exp === 0 ?
1 :
is_even(exp) ?
square(expmod(base, exp / 2, m)) % m :
base * expmod(base, exp - 1, m) % m;
}
function expmod1(base, exp, m) {
return fast_expt(base, exp) % m;
}
function timed_expmod(base, exp, m) {
let t = get_time();
display(expmod(base, exp, m));
display(get_time() - t);
t = get_time();
display(expmod1(base, exp, m));
t = get_time();
display(get_time() - t);
}
function iter(n) {
if (n > 0) {
let base = math_floor(math_random() * 1000),
exp = math_floor(math_random() * 1000),
m = math_floor(math_random() * 100);
display(`base = ${base}, exp = ${exp}, m = ${m}`);
timed_expmod(base, exp, m);
iter(n - 1);
}
}
iter(20);
timed_expmod(2, 5, 3);
入出力結果(Terminal, Zsh)
% node answer1.25.js
base = 112, exp = 208, m = 56
0
0.4781380295753479
NaN
0.0021019577980041504
base = 746, exp = 359, m = 53
25
0.14439600706100464
NaN
0.014458954334259033
base = 939, exp = 942, m = 86
1
0.12046104669570923
NaN
0.0021250247955322266
base = 733, exp = 790, m = 89
22
0.09960198402404785
NaN
0.0011680126190185547
base = 290, exp = 804, m = 79
21
0.02437901496887207
NaN
0.001123964786529541
base = 406, exp = 852, m = 95
1
0.18944597244262695
NaN
0.0035860538482666016
base = 672, exp = 537, m = 62
58
0.02233600616455078
NaN
0.0006740093231201172
base = 721, exp = 787, m = 86
63
0.033877015113830566
NaN
0.0005739927291870117
base = 357, exp = 758, m = 99
81
0.02478998899459839
NaN
0.000558018684387207
base = 527, exp = 294, m = 49
1
0.018157005310058594
NaN
0.0009079575538635254
base = 584, exp = 694, m = 48
16
0.018281996250152588
NaN
0.0004660487174987793
base = 876, exp = 387, m = 47
23
0.017250001430511475
NaN
0.00048804283142089844
base = 963, exp = 635, m = 55
32
0.01661604642868042
NaN
0.0004850029945373535
base = 97, exp = 671, m = 99
31
0.022660017013549805
NaN
0.0029739737510681152
base = 129, exp = 599, m = 64
1
0.01907801628112793
NaN
0.0005199909210205078
base = 562, exp = 759, m = 93
70
0.019347012042999268
NaN
0.0006530284881591797
base = 678, exp = 771, m = 55
7
0.021675944328308105
NaN
0.0005180239677429199
base = 467, exp = 276, m = 72
1
0.016160011291503906
NaN
0.0015990138053894043
base = 336, exp = 338, m = 40
16
0.027198970317840576
NaN
0.0005449652671813965
base = 141, exp = 715, m = 1
0
0.017455995082855225
NaN
0.0005429983139038086
2
0.02722698450088501
2
0.0005509853363037109
%
実際に確認してみたら、大きな累乗を求める際にJavaScriptのnumberの範囲の上限を超えてInfinityになり、そのある数の剰余はNaNになってしまうみたい。ただ、小さい数字の場合には、fast_exptを使用した方が速い。