一个简单系列的奇怪和意想不到的结果
Weird and unexpected results from a simple series
我用一个简单的 JS 代码计算了以下系列的总和:
b
是一个常量,可以是任意值。
JS 代码试图找到 minimum 值 r
(在本例中给出 1000 次尝试),这个不等式是有效的:
如果 r
低于 1.50000
,结果会很糟糕。
var pre = 0.0;
var r = 1.50010;
var b = 0.01;
for (var p = 0; p < 1000; p++) {
var sum = 0;
for (var i = 0; i <= 33; i++) {
sum += Math.pow(r, i);
}
sum *= b;
if ((2 * b * Math.pow(r, 34)) > sum) {
pre = r;
r -= 0.00001;
r = parseFloat(r.toFixed(5));
} else {
console.log(pre);
console.log(((2 * b * Math.pow(r + 0.00001, 34)) - sum).toFixed(8));
break;
}
}
代码在 pre == 1.5
中断,如果我强制 r = 1.49999
,console.log(pre)
returns 0
。为什么?
代码在 r = 1.5 时停止,因为这是不等式有效的最小值(无论如何在您使用的精度范围内)。如果你开始 r off 小于那个值,它会在第一次通过循环时中断,因为 if 语句永远不会为真,所以你永远不会将 pre 设置为 r.
这是一张图表,显示了在 r = 1.5 附近不等式两侧发生的情况:
上图的代码:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1.4, 1.6, 100)
plt.plot(x , 2 * x ** 34, label = 'r^{34}$')
plt.plot(x , sum([x ** i for i in xrange(34)]), label = '$\sum_{i = 0}^{33}\/ r^i$')
plt.yscale('log')
plt.legend()
plt.show()
此外,如果 b 为正,则您无需在代码中对 b 执行任何操作,因为您将不等式的两边都乘以 b。而如果b是负数,则需要对不等式进行倒转。
哦,还有一件事:对于这种类型的算法,您可能需要考虑更像 bisection method 的东西,它每次通过迭代将搜索 space 减半。您可以使用 1 和 2 作为端点,因为 1 绝对太低而 2 绝对太高。当不等式两边的差异低于某个阈值时,你会停止。
我假设当循环中断时,您想要显示不等式左右的差异。问题是因为 "sum" 是来自上一个循环的 运行 总和,计算不正确。
现在,当您强制 r = 1.49999 时,if 子句永远不会执行,因此 "pre" 保持在第一行启动时的零。
你的完整解决方案应该是这样的:
var pre = 0.0;
var r = 1.50010;
var b = 0.01;
for (var p = 0; p < 1000; p++) {
var sum = 0;
for (var i = 0; i <= 33; i++) {
sum += Math.pow(r, i);
}
sum *= b;
var diff = (2 * b * Math.pow(r, 34) - sum).toFixed(8);
console.log('diff: ' + diff);
if ((2 * b * Math.pow(r, 34)) > sum) {
pre = r;
r -= 0.00001;
r = parseFloat(r.toFixed(5));
} else {
console.log('--breaking--');
console.log(pre);
//console.log(((2 * b * Math.pow(r + 0.00001, 34)) - sum).toFixed(8));
break;
}
}
输出为:
diff: 3.91098781
diff: 3.52116542
diff: 3.13150396
diff: 2.74200338
diff: 2.35266364
diff: 1.96348468
diff: 1.57446646
diff: 1.18560893
diff: 0.79691205
diff: 0.40837575
diff: 0.02000000
diff: -0.36821526
--breaking--
1.5
我用一个简单的 JS 代码计算了以下系列的总和:
b
是一个常量,可以是任意值。
JS 代码试图找到 minimum 值 r
(在本例中给出 1000 次尝试),这个不等式是有效的:
如果 r
低于 1.50000
,结果会很糟糕。
var pre = 0.0;
var r = 1.50010;
var b = 0.01;
for (var p = 0; p < 1000; p++) {
var sum = 0;
for (var i = 0; i <= 33; i++) {
sum += Math.pow(r, i);
}
sum *= b;
if ((2 * b * Math.pow(r, 34)) > sum) {
pre = r;
r -= 0.00001;
r = parseFloat(r.toFixed(5));
} else {
console.log(pre);
console.log(((2 * b * Math.pow(r + 0.00001, 34)) - sum).toFixed(8));
break;
}
}
代码在 pre == 1.5
中断,如果我强制 r = 1.49999
,console.log(pre)
returns 0
。为什么?
代码在 r = 1.5 时停止,因为这是不等式有效的最小值(无论如何在您使用的精度范围内)。如果你开始 r off 小于那个值,它会在第一次通过循环时中断,因为 if 语句永远不会为真,所以你永远不会将 pre 设置为 r.
这是一张图表,显示了在 r = 1.5 附近不等式两侧发生的情况:
上图的代码:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(1.4, 1.6, 100)
plt.plot(x , 2 * x ** 34, label = 'r^{34}$')
plt.plot(x , sum([x ** i for i in xrange(34)]), label = '$\sum_{i = 0}^{33}\/ r^i$')
plt.yscale('log')
plt.legend()
plt.show()
此外,如果 b 为正,则您无需在代码中对 b 执行任何操作,因为您将不等式的两边都乘以 b。而如果b是负数,则需要对不等式进行倒转。
哦,还有一件事:对于这种类型的算法,您可能需要考虑更像 bisection method 的东西,它每次通过迭代将搜索 space 减半。您可以使用 1 和 2 作为端点,因为 1 绝对太低而 2 绝对太高。当不等式两边的差异低于某个阈值时,你会停止。
我假设当循环中断时,您想要显示不等式左右的差异。问题是因为 "sum" 是来自上一个循环的 运行 总和,计算不正确。
现在,当您强制 r = 1.49999 时,if 子句永远不会执行,因此 "pre" 保持在第一行启动时的零。
你的完整解决方案应该是这样的:
var pre = 0.0;
var r = 1.50010;
var b = 0.01;
for (var p = 0; p < 1000; p++) {
var sum = 0;
for (var i = 0; i <= 33; i++) {
sum += Math.pow(r, i);
}
sum *= b;
var diff = (2 * b * Math.pow(r, 34) - sum).toFixed(8);
console.log('diff: ' + diff);
if ((2 * b * Math.pow(r, 34)) > sum) {
pre = r;
r -= 0.00001;
r = parseFloat(r.toFixed(5));
} else {
console.log('--breaking--');
console.log(pre);
//console.log(((2 * b * Math.pow(r + 0.00001, 34)) - sum).toFixed(8));
break;
}
}
输出为:
diff: 3.91098781
diff: 3.52116542
diff: 3.13150396
diff: 2.74200338
diff: 2.35266364
diff: 1.96348468
diff: 1.57446646
diff: 1.18560893
diff: 0.79691205
diff: 0.40837575
diff: 0.02000000
diff: -0.36821526
--breaking--
1.5