開発環境
- macOS Sierra - Apple (OS)
- Emacs (Text Editor)
- JavaScript (プログラミング言語)
- JavaScript Library
- Safari(Web browser)
- 参考書籍
- JavaScript 第6版 (David Flanagan(著)、村上 列(翻訳)、オライリージャパン)
- JavaScriptリファレンス 第6版(David Flanagan(著)、木下 哲也(翻訳)、オライリージャパン)
計算機プログラムの構造と解釈[第2版](ハロルド エイブルソン (著)、ジュリー サスマン (著)、ジェラルド・ジェイ サスマン (著)、Harold Abelson (原著)、Julie Sussman (原著)、Gerald Jay Sussman (原著)、和田 英一 (翻訳)、翔泳社、原著: Structure and Interpretation of Computer Programs (MIT Electrical Engineering and Computer Science)(SICP))の第1章(手続きによる抽象の構築)、1.3(高階手続きによる抽象)、1.3.4(値として返される手続き)、問題1.40.を JavaScript で取り組んでみる。
その他参考書籍
問題1.40.
コード(Emacs)
HTML5
<math> <mrow> <mi>f</mi><mrow><mo>(</mo> <mi>x</mi> <mo>)</mo></mrow><mo>=</mo><msup> <mi>x</mi> <mn>3</mn> </msup> <mo>+</mo><mi>a</mi><msup> <mi>x</mi> <mn>2</mn> </msup> <mo>+</mo><mi>b</mi><mi>x</mi><mo>+</mo><mi>c</mi> </mrow> </math> <script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> <div id="graph0"></div> <div id="xs0"></div> <label for="a0">a = </label> <input id="a0" type="number" step="1" value="1"> <label for="b0">b = </label> <input id="b0" type="number" step="1" value="2"> <label for="c0">c = </label> <input id="c0" type="number" step="1" value="3"> <label for="guess0">予測値: </label> <input id="guess0" type="number" step="1" value="1"> 零点の近似: f(<span id="zero0"></span>) = <span id="fx0"></span> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script> <script src="sample40.js"></script>
JavaScript
{
'use strict';
Array.range = function (start, end, step) {
var nums = [],
i;
if (step === 0) {
throw {
name: 'ValueError',
message: 'range() arg 3 must not be zero',
};
}
if (step === undefined) {
step = 1;
}
if (end === undefined) {
end = start;
start = 0;
}
if (step > 0) {
for (i = start; i < end; i += step) {
nums.push(i);
}
} else {
for (i = start; i > end; i += step) {
nums.push(i);
}
}
return nums;
};
let svg,
width = 600,
height = 600,
padding = 50,
xscale,
yscale,
min,
max,
xaxis,
yaxis,
div_graph = document.querySelector('#graph0'),
div_xs = document.querySelector('#xs0'),
input_a = document.querySelector('#a0'),
input_b = document.querySelector('#b0'),
input_c = document.querySelector('#c0'),
input_guess = document.querySelector('#guess0'),
inputs = [input_a, input_b, input_c, input_guess],
span_zero = document.querySelector('#zero0'),
span_fx = document.querySelector('#fx0'),
tolerance = 0.00001,
xs,
ys,
fixedPoint = (f, first_guess) => {
let isCloseEnough = (v1, v2) => {
return Math.abs(v1 - v2) < tolerance;
};
xs = [first_guess];
let tryFunc = (guess) => {
let next = f(guess);
xs.push(next);
if (isCloseEnough(guess, next)) {
return next;
}
return tryFunc(next);
};
return tryFunc(first_guess);
},
dx = 0.00001,
deriv = (g) => {
return (x) => (g(x + dx) - g(x)) / dx;
},
newtonsTransform = (g) => {
return (x) => x - g(x) / deriv(g)(x);
},
newtonsMethod = (g, guess) => fixedPoint(newtonsTransform(g), guess),
cubic = (a, b, c) => {
return (x) => Math.pow(x, 3) + a * Math.pow(x, 2) + b * x + c;
},
output = () => {
let a = parseFloat(input_a.value),
b = parseFloat(input_b.value),
c = parseFloat(input_c.value),
guess = parseFloat(input_guess.value),
x = newtonsMethod(cubic(a, b, c), guess);
span_zero.innerText = x;
div_xs.innerHTML = `収束の様子<br>${xs.join('<br>')}`;
let func = cubic(a, b, c);
ys = xs.map(func);
span_fx.innerText = ys[ys.length - 1];
max = Math.max.apply(null, xs.concat(ys).map(Math.abs));
min = -max;
let points = Array.range(min, max, 0.01)
.map((x) => [x, func(x), 1, 'blue'])
.filter((point) => min < point[1] && point[1] < max);
xscale = d3.scaleLinear()
.domain([min, max])
.range([padding, width - padding]);
yscale = d3.scaleLinear()
.domain([min, max])
.range([height - padding, padding]);
xaxis = d3.axisBottom().scale(xscale);
yaxis = d3.axisLeft().scale(yscale);
points = points.map((point) => [xscale(point[0]), yscale(point[1]),
point[2], point[3]])
.concat(xs.map((x, i) => {
return [xscale(x), yscale(ys[i]), 4, 'green'];
}));
div_graph.innerHTML = '';
svg = d3.select('#graph0')
.append('svg')
.attr('width', width)
.attr('height', height);
svg.selectAll('circle')
.data(points)
.enter()
.append('circle')
.attr('cx', (d) => d[0])
.attr('cy', (d) => d[1])
.attr('r', (d) => d[2])
.attr('fill', (d) => d[3]);
svg.append('line')
.attr('x1', xscale(min))
.attr('y1', yscale(0))
.attr('x2', xscale(max))
.attr('y2', yscale(0))
.attr('stroke', 'black');
svg.append('g')
.attr('transform', `translate(0, ${height / 2})`)
.call(xaxis);
svg.append('g')
.attr('transform', `translate(${width / 2}, 0)`)
.call(yaxis);
};
inputs.forEach((input) => {
input.onchange = output;
});
output();
}
零点の近似: f() =
0 コメント:
コメントを投稿