这段代码有很多问题。
首先,在这样的循环中添加浮点数会增加浮点格式的二进制错误,直到它们在输出中变得明显。尝试运行此代码:
var a = [];
for (var i = 0; i < 2 * Math.PI; i += 0.02)
a.push(i);
$('#output').html(a.join('<br/>'));
http://jsfiddle.net/b9chris/AwT5c/
看看它产生的值。这可能不是你所期望的。这些疯狂的数字是浮点数存储方式的结果 - 小数部分存储为二进制小数,因此 1/2 + 1/4 + 1/8 + ... 。0.02 无法以这种格式精确表示,因此系统会对其进行近似,然后在返回时将值四舍五入到小数点后 10 位,从而覆盖伪造的基础值。但是加法是用二进制完成的,最终近似值加起来揭示了这个问题。
解决方案是用整数循环并尽可能晚地除法:
http://jsfiddle.net/b9chris/AwT5c/1/
其次,您的循环条件包括一个始终返回相同结果的操作。这会浪费 CPU 时间 - for 循环将不断重新计算 2 * Math.PI 的值,只是为了在每个循环中获得完全相同的结果。您可以通过将其存储在变量中并针对该变量运行循环来解决此问题。
你可能不明白 Array.push() 是如何工作的。您将一个值传递给它,它会自动将其分配给数组中的下一个索引。因此,在其中包含 1 个值的数组上运行:
a.push([5, 10]);
在索引 1(不是 5)处添加一个值,该值本身就是一个 2 项数组,[5, 10]
. 所以你在哪里做这个:
d1.push([i, 1]);
var d = d1[i][1];
例如,您在索引 0 处添加一个值,然后尝试在索引 0.02 处将其取回。由于您的目标是通过索引直接访问它们,因此使用 push 并不安全,然后假设索引与循环计数器中的内容匹配(例如,如果数组已经添加了值怎么办)。而是直接按索引分配,这在 Javascript 中是允许的。
最后,您应该避免像这样将所有内容都转储到全局范围内 - 使用 var 关键字将它们限定在本地范围内。
var d1 = [];
var d2 = [];
var d3 = [];
var inverseStep = 50; // 1 / .02
var l = 2 * Math.PI * inverseStep;
for (var i = 0; i < l; i++) {
var ix = i / inverseStep;
d1[i] = [ix, 15+Math.sin(5*ix)];
d2[i] = [ix, 10+Math.sin(4*ix)];
var d = d1[i][1] + d2[i][1];
d3[i] = [ix, d];
}
$('#output').html(d3.join('<br/>'));
http://jsfiddle.net/b9chris/AwT5c/3/