2016年10月1日土曜日

開発環境

計算機プログラムの構造と解釈[第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( x )= x 3 +a x 2 +bx+c
零点の近似: f() =

0 コメント:

コメントを投稿