Public
Edited
Mar 12, 2024
Importers
1 star
Insert cell
Insert cell
f = x => (x + 3) * (x - 1) ** 3
Insert cell
function updateDividedDiffs(xvals, divdiffs, x, fx, k) {
xvals.unshift(x);
divdiffs.unshift(fx);
for (let i = 1; i <= xvals.length; i++)
divdiffs[i] = (divdiffs[i] - divdiffs[i - 1]) / (xvals[i] - xvals[0]);
if (xvals.length > k + 1) {
xvals.pop();
divdiffs.pop();
}
}
Insert cell
function sidi(f, k) {
const xvals = [0, 1],
divdiffs = [f(xvals[1])];

updateDividedDiffs(xvals, divdiffs, xvals.shift(), f(xvals[0]), k);

return { divdiffs };
}
Insert cell
sidi(f, 2)
Insert cell
Sidi_method(f, -100, 1000)
Insert cell
Sidi_method(Math.cos, 0, 1, 0.99)
Insert cell
// https://github.com/susiang100/cejs/blob/master/data/math.js#L1302
/**
* 求根/求取反函數 equation^-1(y)。 using Sidi's generalized secant method.
*
* @param {Function}equation
* 演算式, mapping function
* @param {Number}x0
* 求值之自變數 variable 下限,設定初始近似值。
* @param {Number}x1
* 求值之自變數 variable 上限,設定初始近似值。
* @param {Number}[y]
* 目標值。default: 0. get (equation^-1)(y)
* @param {Object}[options]
* options 設定特殊功能:<br />
*
* @returns {Number}root: equation(root)≈y
*
* @see https://en.wikipedia.org/wiki/Root-finding_algorithm
* @see https://en.wikipedia.org/wiki/Sidi's_generalized_secant_method
*/
function Sidi_method(equation, x0 = 0, x1 = 1, y, options) {
// default error, accuracy, stopping tolerance, 容許誤差
var error = Number.EPSILON;
if (!options) options = {};
else if (options > 0) error = options;
else if (options.error > 0) error = Math.abs(options.error);

y = +y || 0;

var count = (options.count || 40) | 0,
// assert: y0 = equation(x0)
y0 = 'y0' in options ? options.y0 : equation(x0),
// assert: y1 = equation(x1)
y1 = 'y1' in options ? options.y1 : equation(x1);

if (
typeof options.start_OK === 'function' &&
// 初始測試: Invalid initial value, 不合理的初始值,因此毋須繼續。
!options.start_OK(y0, y1)
)
return;

// initialization
var x2 = x1 - ((x1 - x0) * (y1 - y)) / (y1 - y0),
//
y2 = equation(x2),
x3 = x2,
y3 = y2,
// divided differences, 1階差商
y10 = (y1 - y0) / (x1 - x0),
y21 = (y2 - y1) / (x2 - x1),
// 2階差商
y210 = (y21 - y10) / (x2 - x0),
// 暫時使用。
denominator;

// main loop of Sidi's generalized secant method (take k = 2)
while (
error < Math.abs(y3 - y) &&
count-- > 0 &&
// 檢查是否兩個差距極小的不同輸入,獲得相同輸出。
y21 !== 0 &&
// 分母不應為 0 或 NaN。
(denominator = y21 + y210 * (x2 - x1)) &&
// Avram Sidi (2008), "Generalization Of The Secant Method For Nonlinear
// Equations"
// 可能需要考量會不會有循環的問題。
((x3 = x2 - (y2 - y) / denominator) !== x2 || x2 !== x1 || x1 !== x0)
) {
// evaluate result
y3 = equation(x3);
// console.log(count + ': ' + x3 + ',' + y3 + ' → error ' + (y3 - y));
// shift items
(x0 = x1), (y0 = y1);
(x1 = x2), (y1 = y2);
(x2 = x3), (y2 = y3);
// reckon divided differences
y10 = y21;
y21 = (y2 - y1) / (x2 - x1);
// y210 = (y21 - y10) / (x2 - x0);
// incase y21 === y10
if ((y210 = y21 - y10)) y210 /= x2 - x0;
// console.log('divided differences: ' + [ y10, y21, y210 ]);
}

return { x: x3, count: 40 - count, fm: y3 - y };
}
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more