0

我正在尝试创建 2 个正弦波并将它们加在一起以创建第三个。我可以很好地添加它们并将结果输出到控制台,但是每当我尝试将此值放入数组时,我都会收到错误消息:

“无法读取未定义的属性 '1'”

谁能解释我哪里出错了?Jsfiddle在这里:http: //jsfiddle.net/YJqZz/

d1 = [];
d2 = [];
d3 = [];

// Sample the sine function
for (i = 0; i < 2 * Math.PI; i += 0.02) {
    d1.push([i, 15+Math.sin(5*i)]);
    d2.push([i, 10+Math.sin(4*i)]);
    console.log(d1[i][1] + d2[i][1]);
    d = d1[i][1] + d2[i][1];
    console.log(d);
    d3.push([i,d]);
}
4

3 回答 3

4

dX访问最后一个正在使用的元素dx[dX.length - 1]

i在这里漂浮(0.02)。该值不是整数,而是转换为字符串。然后 Array 对象被解释为常规对象(一种映射)。对象中没有键"0.02",因此dX["0.02"]计算结果为undefined。您无法访问undefined,因此会出错。

于 2013-06-22T18:24:01.610 回答
4

您正在尝试使用双精度访问 Array 中的元素,因为您的循环递增0.02. Array 的键在你 push 时被设置为整数,所以这个方法不起作用。

我已经重构您的代码以使用 Objects 代替:http: //jsfiddle.net/YJqZz/2/

d1 = {};
d2 = {};
d3 = {};

// Sample the sine function
for (i = 0; i < 2 * Math.PI; i += 0.02) {
  d1[i] = [i, 15+Math.sin(5*i)];
  d2[i] = [i, 10+Math.sin(4*i)];
  console.log(d1[i][1] + d2[i][1]);
  d = d1[i][1] + d2[i][1];
  console.log(d);
  d3[i] = [i,d];
}
于 2013-06-22T18:24:56.687 回答
1

这段代码有很多问题。

首先,在这样的循环中添加浮点数会增加浮点格式的二进制错误,直到它们在输出中变得明显。尝试运行此代码:

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/

于 2013-06-23T22:29:27.713 回答