(An addition to the answer by C. E.)
It is interesting that behavior of Total
in Mathematica 12 indeed depends on the length of the list according to Trace
. Let us compare:
arr = Table[0.979, 249];
Trace[Total[arr], TraceInternal -> True] /. {arr -> "arr",
p : HoldForm[Plus[__]] :> Shallow[p, 3]}
{{arr, "arr"}, Total["arr"], {$MessageList={}, {}}, {Plus@@"arr", Plus[<<249>>], 243.771}, {$MessageList, {}}, 243.771}
arr = Table[0.979, 250];
Trace[Total[arr], TraceInternal -> True] /. {arr -> "arr",
p : HoldForm[Plus[__]] :> Shallow[p, 3]}
{{arr, "arr"}, Total["arr"], 244.75}
Using Developer`PackedArrayQ
we find that in the first case the array generated by Table
isn't packed, while in the second case it is a packed array. Let us compare the results for the same unpacked and packed array:
arr = Table[0.979, 249];
arrPacked = Developer`ToPackedArray@arr;
{Plus @@ arr - Total[arr], Plus @@ arrPacked - Total[arrPacked],
Plus @@ arr - Total[arrPacked]}
{0., 1.13687*10^-13, 1.13687*10^-13}
We see that the result of such a simple summation of identical numbers by Total
strongly depends on whether the array is packed or not.
Comparison with other summation methods reveals that we have at least 4 built-in methods giving different results:
arr = Table[0.979, 249];
sum = 0; Do[sum += 0.979, 249];
{Fold[Plus, arr],
Plus @@ arr,
Total[arr, Method -> "CompensatedSummation"],
Total[Developer`ToPackedArray@arr]} - sum
{0., -1.53477*10^-12, -1.50635*10^-12, -1.64846*10^-12}
It is interesting to compare results of summations with multiplication:
{Fold[Plus, arr],
Plus @@ arr,
Total[arr, Method -> "CompensatedSummation"],
Total[Developer`ToPackedArray@arr]} - 0.979*249
{1.50635*10^-12, -2.84217*10^-14, 0., -1.42109*10^-13}
Surprisingly, Method -> "CompensatedSummation"
produces the same result as multiplication!
Obviously the order of summation cannot matter here because all the numbers are identical. What can matter, for example, is the size of a chunk when the summation is performed in chunks:
sums = Table[N@ArrayReshape[arr, Table[n, Ceiling@N@Log[n, 249]]]
//. {x__Real} :> Plus[x], {n, 2, 50}];
sums - Plus @@ arr
% // Abs // Max
{5.68434*10^-14, 5.68434*10^-14, 5.68434*10^-14, 2.84217*10^-14, 5.68434*10^-14,
2.84217*10^-14, 5.68434*10^-14, 5.68434*10^-14, 2.84217*10^-14, 0., 5.68434*10^-14,
2.84217*10^-14, 2.84217*10^-14, 2.84217*10^-14, 5.68434*10^-14, 5.68434*10^-14,
5.68434*10^-14, 2.84217*10^-14, 2.84217*10^-14, 0., 0., 0., 5.68434*10^-14,
5.68434*10^-14, 5.68434*10^-14, 5.68434*10^-14, 2.84217*10^-14, 2.84217*10^-14,
2.84217*10^-14, 2.84217*10^-14, 5.68434*10^-14, 5.68434*10^-14, 5.68434*10^-14,
2.84217*10^-14, 5.68434*10^-14, 5.68434*10^-14, 2.84217*10^-14, 0., 2.84217*10^-14,
2.84217*10^-14, 0., 0., 0., 0., 0., 0., 2.84217*10^-14, 5.68434*10^-14, 5.68434*10^-14}
5.68434*10^-14
These differences doesn't explain however the discrepancy of size 10^-12 which we get with built-in methods.
Let us compare with one-by-one summation in chunks:
sums = Table[N@ArrayReshape[arr, Table[n, Ceiling@N@Log[n, 249]]]
//. l : {__Real} :> Fold[Plus, l], {n, 2, 249}];
sums - Plus @@ arr // Abs // Max
ListPlot[sums - Plus @@ arr]
1.53477*10^-12
The linear growth of the discrepancy starts at n = 131
. It isn't clear for me from where comes this digit: "FoldCompileLength"
is by default set to 100
and changing this option doesn't affect the plot.
arr = Developer`ToPackedArray[arr]
. I would have guessed that the different result is simply due to the summation being done in a different order, but I don't understand how this relates to the array being packed. $\endgroup$Method->"CompensatedSummation"
for both and compare... $\endgroup$