0

I'm trying to create 2 sine waves and add them together to create a third. I can add them fine and output the result to the console, but whenever I try to put this value into an array, I get the error :

"Cannot read property '1' of undefined"

Can anyone explain where I'm going wrong? Jsfiddle here: 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]);
}
2
  • Sounds like d1[i] or d2[i] doesn't exist. If d1[i] is undefined, you can't do undefined[1] Commented Jun 22, 2013 at 18:21
  • 2
    when you push(), your elements will have integer indices, like 2. but, your i variable isnt an int, its something like 0.04 Commented Jun 22, 2013 at 18:23

3 Answers 3

4

To access the last element in dX use dx[dX.length - 1].

Your i is float in here (0.02). The value, not being an integer, is casted to a string. Then the Array object is interpreted as a regular object (kind of a map). There is no key "0.02" in the object, so dX["0.02"] evaluates to undefined. You cannot access undefined, hence to error.

Sign up to request clarification or add additional context in comments.

2 Comments

"The value, not being an integer, is casted to a string." Array indexes are always strings. (In the classic JavaScript arrays, not the new ones.) (Don't get me wrong, I think I was your first upvote because this was the first answer to put its finger on the problem correctly. I'm just saying...)
Array indexes are never strings. The indexer syntax a[value] accesses either array indices or object properties. If you use a number like a[0], the number is used as-is - not cast to a string - and accesses the array value at index 0, if any. If you use a string like a['Name'], this accesses the object property named 'Name', if any. This is identical to accessing a.Name.
4

You're trying to access the elements in the Array with doubles, as your loop increments by 0.02. The keys of an Array are set as integers when you push, so this method will not work.

I've refactored your code to use Objects instead: 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];
}

1 Comment

Always put the relevant code in the answer itself, rather than just linking. (Even with jsFiddle.) Why: meta.stackexchange.com/questions/118392/… I was in there fixing a typo anyway, so I just copied it over for you.
1

There are a lot of problems with this code.

First, adding floats in a loop like this will increase the binary errors in the floating point format until they become apparent in the output. Try running this code:

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/

Take a look at the values it generated. It's probably not what you expected. Those crazy numbers are a result of the way floating point numbers are stored - the decimal portion is stored as binary decimals, so 1/2 + 1/4 + 1/8 + ... . 0.02 cannot be precisely represented in this format, so the system approximates it then rounds the value to base 10 decimals when it comes back out, covering over the fudged underlying value. But the additions are done in binary, and eventually the approximations add up and reveal this problem.

The solution is to instead loop with integers and divide as late as possible:

http://jsfiddle.net/b9chris/AwT5c/1/

Second, your loop condition includes an operation that always returns the same result. This wastes CPU time - the for loop will constantly recalculate the value of 2 * Math.PI only to get the exact same result each loop. You can resolve this by storing it in a variable and running the loop against that instead.

You might not understand how Array.push() works. You pass it a value to push and it automatically assigns that to the next index in the array. So this, run on an array with 1 value in it:

a.push([5, 10]);

Adds a value at index 1 (not 5), and that value is itself a 2-item array, [5, 10]. So where you were doing this:

d1.push([i, 1]);
var d = d1[i][1];

You were adding a value at index 0, for example, then attempting to get it back out at index 0.02. Since your goal is to directly access them by index, it's not really safe to use push then assume the index matches what's in the loop counter (for example, what if the array already had values added to it). Instead assign by index directly, which is permissible in Javascript.

Finally, you should avoid dumping everything into the global scope like this - scope them local with the var keyword.

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/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.