/** * Polynomial interpolation * by Kazuki Maeda * Last-Modified: Dec 10, 2025 */ const canvasW = 600; const canvasH = 600; const minX = -1; const maxX = 1; const minY = -2; const maxY = 2; const numPoints = 11; const numSamples = 401; let s; let targetIndex = -1; function setup(){ let canvas = createCanvas(canvasW, canvasH); document.getElementById('reset').addEventListener('click', reset, true); document.getElementById('hardmode').addEventListener('change', Draw, true); canvas.parent('canvas'); reset(); } function reset(){ s = [...Array(numPoints).keys()].map((n) => {return [-1+2/(numPoints-1)*n, f(-1+2/(numPoints-1)*n)]}); Draw(); } function XtoCanvasX(x){ return canvasW/(maxX-minX)*(x-minX); } function YtoCanvasY(y){ return canvasH/(minY-maxY)*(y-maxY); } function CanvasXtoX(x){ return (maxX-minX)/canvasW*x+minX; } function CanvasYtoY(y){ return (minY-maxY)/canvasH*y+maxY; } function lineGraph(x1, y1, x2, y2){ line(XtoCanvasX(x1), YtoCanvasY(y1), XtoCanvasX(x2), YtoCanvasY(y2)); } function ellipseGraph(x, y, width, height){ ellipse(XtoCanvasX(x), YtoCanvasY(y), width, height); } function f(x){ return 1.0/(1+25*x**2); } function P(x, s){ let r = 0; for(let j = 0; j < s.length; ++j){ let p = s[j][1]; // yj for(let i = 0; i < s.length; ++i) if(i != j) p *= (x-s[i][0])/(s[j][0]-s[i][0]); // (x-xi)/(xj-xi) r += p; } return r; } function drawGraph(f){ for(let i = 0; i < numSamples-1; ++i){ const x1 = minX + (maxX-minX)/(numSamples-1)*i; const x2 = minX + (maxX-minX)/(numSamples-1)*(i+1); const y1 = f(x1); const y2 = f(x2); lineGraph(x1, y1, x2, y2); } } function drawInterpolationGraph(P, s){ for(let i = 0; i < numSamples-1; ++i){ const x1 = minX + (maxX-minX)/(numSamples-1)*i; const x2 = minX + (maxX-minX)/(numSamples-1)*(i+1); const y1 = P(x1, s); const y2 = P(x2, s); lineGraph(x1, y1, x2, y2); } } // Not draw() function Draw(){ strokeWeight(1); background(0); stroke(128); for(let x = minX+(maxX-minX)/20; x < maxX; x += (maxX-minX)/20) lineGraph(x, minY, x, maxY); stroke(255); lineGraph(minX, 0, maxX, 0); // x axis lineGraph(0, minY, 0, maxY); // y axis strokeWeight(3); stroke(0x7f, 0xff, 0); drawGraph(f); stroke(0xff, 0x7f, 0); drawInterpolationGraph(P, s); fill(0xff, 0x7f, 0); for(let i = 0; i < s.length; ++i){ ellipseGraph(s[i][0], s[i][1], 10, 10); } updateResult(); } function updateResult(){ let resulttext = 'Maximum Error: '; let maxErr = 0; let maxErrX = 0; for(let i = 0; i < numSamples; ++i){ let x = minX + (maxX-minX)/(numSamples-1)*i; let err = Math.abs(f(x)-P(x, s)); if(err > maxErr){ maxErr = err; maxErrX = x; } } if(!document.getElementById('hardmode').checked){ stroke(0xff, 0, 0); lineGraph(maxErrX, f(maxErrX), maxErrX, P(maxErrX, s)); } resulttext += maxErr.toPrecision(6).toString(); stroke(0); fill(0xff, 0x7f, 0); textSize(20); textFont('monospace'); text(resulttext, 20, 40); let points = [...Array(numPoints).keys()].map((n) => {return s[n][0];}); points.sort((a, b) => {return a-b;}); resulttext = 'Points: '; for(let n = 0; n < numPoints; ++n){ resulttext += points[n].toPrecision(3).toString(); if(n != numPoints-1) resulttext += ', '; } textSize(12); text(resulttext, 20, 60); } function mouseAction(){ let X = CanvasXtoX(mouseX); let Y = CanvasYtoY(mouseY); if(minX <= X && X <= maxX && minY <= Y && Y <= maxY){ if(targetIndex == -1){ let minnorm2 = 10000; for(let n = 0; n < numPoints; ++n){ if(!document.getElementById('allowc').checked && n === parseInt(numPoints/2)) continue; if((s[n][0]-X)**2 < minnorm2){ minnorm2 = (s[n][0]-X)**2; targetIndex = n; } } } s[targetIndex] = [X, f(X)]; } Draw(); } function mouseDragged(){ mouseAction(); } function mousePressed(){ targetIndex = -1; mouseAction(); }