一直以来我都觉得迭代器模式在js中毫无用武之地,直到我发现它可以用来求解方程。
以下是使用迭代器模式在 TypeScript 中实现牛顿迭代法求解实数开平方的示例代码:
-
首先,定义一个迭代器接口
IIterator,它包含两个方法:hasNext()和next()。这将允许我们在迭代过程中检查是否还有下一个值,并返回迭代的下一个值。
interface IIterator {
hasNext(): boolean;
next(): number;
}
-
然后,创建一个具体的迭代器
SqrtIterator,它实现了IIterator接口。在每次调用next()方法时,它将根据牛顿迭代法计算下一个近似值。
class SqrtIterator implements IIterator {
private readonly number: number; // 要求解开平方的数
private readonly epsilon: number; // 迭代精度
private guess: number; // 初始猜测值为 number 的一半
constructor(number: number, epsilon = 1e-6) {
this.number = number;
this.epsilon = epsilon;
this.guess = number / 2;
}
hasNext(): boolean {
return Math.abs(this.guess * this.guess - this.number) > this.epsilon;
}
next(): number {
this.guess = (this.guess + this.number / this.guess) / 2;
return this.guess;
}
}
-
最后,使用
SqrtIterator来求解实数的开平方。通过循环调用next()方法,直到迭代结果满足精度要求为止。
function sqrt(number: number): number {
const iterator = new SqrtIterator(number);
let result = 0;
while (iterator.hasNext()) {
result = iterator.next();
}
return result;
}
// 示例用法
console.log(sqrt(16)); // 输出:4.000000250000002
console.log(sqrt(2)); // 输出:1.4142135623746899
通过以上代码,使用迭代器模式在 TypeScript 中实现了牛顿迭代法求解实数开平方的功能。每次调用 next() 方法都会返回一个更接近实际解的近似值,直到满足精度要求为止。
- 改进上述代码,使之能够求解其他简单方程
next(): number {
this.guess = (this.guess + this.number / this.guess) / 2;
return this.guess;
}
修改成:
private calculator: (x: number, y: number) => number; // 外部注入
constructor(number: number, initial:number, epsilon = 1e-6, calculator: (x: number, y: number) => number) {
this.number = number;
this.epsilon = epsilon;
this.guess = initial || number / 2;
this.calculator = calculator;
}
next(): number {
this.guess = this.calculator(this.guess, this.number);
return this.guess;
}
验证:
function calc(number: number, initial: number, calculator: (x: number, y: number) => number): number {
const iterator = new SqrtIterator(number, initial, undefined, calculator);
let result = 0;
while (iterator.hasNext()) {
result = iterator.next();
}
return result;
}
// 示例用法
const sqrt: (x: number, y: number) => number = (x, y) => (x + y / x) / 2;
console.log(calc(16, 8, sqrt)); // 输出:4.000000250000002
console.log(calc(2, 1, sqrt)); // 输出:1.4142135623746899
// 对于y = x**2 + x ,已知 y = 30 求一个 x 解
// 迭代方程写成 x = y/x - 1
// 初始值取1
const exec: (x: number, y: number) => number = (x, y) => y/x - 1;
console.log(calc(30, 1, exec)); // 本来应该输出5的,可惜它发散了,发散了挺好的,更加加深印象