Why is building a table of function values so much slower than just plotting the function?

Here is a function that take some time to evaluate:

n = 1000;
coeffs = RandomVariate[NormalDistribution[], n];
f[x_] := Sum[coeffs[[k]] Sin[k x]/k, {k, 1, n}];

If I just plot the function with 1000 sample points, it takes about 0.24 seconds on my machine:

Plot[Evaluate@f[x], {x, 0, 2 Pi}, PlotPoints -> n, MaxRecursion -> 0] // Timing

On the other hand, if I try to collect 1000 samples of the function into a table, it takes five times as long:

Table[Evaluate@f[x], {x, 0, 2 Pi, 2 Pi/n // N}] // Timing

(Without the // N Mathematica tries to evaluate things symbolically, which is even slower.)

What is going on, and how can I make the Table as fast as the Plot?

• You can save about one-third of the time by removing the redundant Evaluate from your Table expression. Also, this result is entirely dependent on the MaxRecursion setting. If you remove this, or leave it in but increase its value, the plot takes longer than the table. – Verbeia Aug 28 '13 at 3:53
• I used MaxRecursion -> 0 expecting that the Plot would evaluate exactly 1000 regularly spaced sample points, just like the Table. (Well, the Table actually evaluates 1001 points, but close enough.) Is that not true? – Rahul Aug 28 '13 at 4:01
• I've read in few places that Table can be slow. Not sure why now. Yes, you are right, MaxRecursion -> 0 makes sure no more points are taken. – Nasser Aug 28 '13 at 4:06

Try this:

n = 1000;
coeffs = RandomVariate[NormalDistribution[], n];
f[x_] := Sum[coeffs[[k]] Sin[k x]/k, {k, 1, n}];
Plot[Evaluate@f[x], {x, 0, 2. Pi}, PlotPoints -> n, MaxRecursion -> 0,
Mesh -> All] // Timing With[{n = 1000},
First@Timing[Table[Evaluate@f[x], {x, 0, 2. Pi, 2. Pi/n}]]
] 2 times as fast as plot. I remembered my own question difference-of-speed-in-making-a-table on tables some time ago and this trick of making Table much faster. The point is : to keep it packed, need to have all limits be numerics ! When you had n in there, the upper limit was not. So the table was not packed. Now it is.

You could just also write

Table[Evaluate@f[x], {x, 0, 2. Pi, 2. Pi/1000}]

and get the speed advantage. The point again, all its limits needs to be numeric. See above question for more information and additional links on this subject.

Another example

2000 points. Table still about 2 times faster: • Thanks! But for me it seems that the difference is not the presence of n or the addition of With. Doing First@Timing[Table[Evaluate@f[x], {x, 0, 2. Pi, 2. Pi/n}]] is fast while doing First@Timing[Table[Evaluate@f[x], {x, 0, 2 Pi, 2. Pi/n}]] as in my question is slow. (The difference is just one more decimal point.) – Rahul Aug 28 '13 at 5:18
• @Rahul I'm using v7 so I can't check; is the output of RandomVariate a packed array of Real numbers? – Mr.Wizard Aug 28 '13 at 5:26
• @Mr.Wizard: I'm just learning about packed arrays just now, so let me know if this is not how to check: PackedArrayQ is True and the Head of the first element is Real, so yes? – Rahul Aug 28 '13 at 5:34
• @RahulNarain That's correct. I added an answer that you'll have to test yourself but it might be informative. – Mr.Wizard Aug 28 '13 at 5:39
• Having read your linked question I see that With is necessary for multidimensional tables, which I will need in the future, so thanks for that too! Unfortunately I have already given you an upvote and a check mark, so all I can do now is leave an appreciative comment. :) – Rahul Aug 28 '13 at 7:14