17
$\begingroup$

When I ask Mathematica to evaluate

NSum[((-1)^n)/n, {n, 1, 100}]

it returns -0.688172 + 2.11297*10^-16 i

Why is this? (-1)^n is either 1 or -1. I don't know why it is returning a non-real number. Is there a way to avoid this?

$\endgroup$
6
  • 3
    $\begingroup$ wyas to avoid: NSum[((-1)^n)/n, {n, 1, 100}, Method -> "AlternatingSigns"] or N@Sum[((-1)^n)/n, {n, 1, 100}] $\endgroup$
    – kglr
    Feb 24, 2018 at 23:30
  • $\begingroup$ For this sum one can do also N@Sum or Chop@NSum. $\endgroup$
    – corey979
    Feb 24, 2018 at 23:33
  • $\begingroup$ @corey979 Interesting. What is the difference between NSum and N@Sum? $\endgroup$
    – user85798
    Feb 24, 2018 at 23:34
  • 3
    $\begingroup$ Sum gives an exact result (check it), to which you then apply N. And I guess NSum treats every component with machine precision, so there are more opportunities to introduce rounding errors. Interestingly, however, Sum[N@....] and NSum[((-1.).... give correct results. So NSum must have a different implementation. $\endgroup$
    – corey979
    Feb 24, 2018 at 23:38
  • 1
    $\begingroup$ Expecting exact results from approximate numeric calculations is a recipe for disappointment. $\endgroup$
    – user5147
    Feb 25, 2018 at 4:26

3 Answers 3

18
$\begingroup$

Machine floating point arithmetic can produce strange results when the numbers get very small. Here are same ways to deal with it.

Suppress insignificant imaginary parts.

NSum[((-1)^n)/n, {n, 1, 100}] // Chop

-0.688172

Work with exact numbers until the very end (slower).

Sum[((-1)^n)/n, {n, 1, 100}] // N

-0.688172

Use Mathematica's arbitrary precision arithmetic rather than machine arithmetic.

NSum[((-1)^n)/n, {n, 1, 100}, WorkingPrecision -> 16]

-0.688172179310

Use the special method that NSum has for maintaining precision with series that have terms with alternating signs. This is likely to be the best solution for this particular sum.

NSum[((-1)^n)/n, {n, 1, 100}, Method -> "AlternatingSigns"]

-0.688172

$\endgroup$
14
$\begingroup$

NSum uses a combination of analytic and numeric methods. For instance, it computes

(-1)^102.
(*  1. - 1.95968*10^-14 I  *)

with a real exponent instead of an exact integer. It's the same as Exp[102. Log[-1]], which is the same as Exp[I * 102. * Pi], for that is how Power is computed when the exponent is Real. Rounding error in 102. * Pi introduces a small, complex part in the final result.

For more, see the output of

Trace[NSum[((-1)^n)/n, {n, 1, 100}]]

As @kglr pointed out, the way to make Mathematica handle the -1 power appropriately is with

NSum[((-1)^n)/n, {n, 1, 100}, Method -> "AlternatingSigns"]

The fact that Power with a negative base is going to be a complex-valued function when the exponent is an approximate Real can be countered, given the terms are real, by using Re:

NSum[Re[((-1)^n)/n], {n, 1, 100}]
(*  -0.688172  *)

A different approach that uses exact exponents and Real base:

Total[(-1.)^#/# &@Range[100]]
(*  -0.688172  *)

Integer powers are treated differently than floating-point powers. Total tends to be a better way to approach small finite sums.

$\endgroup$
5
  • 2
    $\begingroup$ I think Mathematica floating point handling sometimes can be strange. I tried all these commands shown in the question and answers given, in Maple 2017. used Maple floating points (evalf) (not hardware floating points evalfh) and never got a complex value to show up. I think one needs a PhD in computer science to really understand Mathematica's floating points handling :) $\endgroup$
    – Nasser
    Feb 25, 2018 at 1:06
  • $\begingroup$ @Nasser Did you try exp(102*log(-1)) in Maple? In Matlab, exp(..) gives the Mathematica result, but (-1).^102 gives 1. I think in Matlab and maybe Maple, -1 raised to a floating-point whole number is treated as a special case. OTOH, (-1)^10000000000000001 in Matlab yields 1. -- I rather think in this case, Mathematica's handling is predictably consistent and normal: a^b == Exp[b * Log[a]] and Log[-1] = Pi * I. One should expect a rounding error of at most 102*Pi*$MachineEpsilon/2, which is about what we get. IMO, the issue not floating point, but the def. of (-1)^x. $\endgroup$
    – Michael E2
    Feb 25, 2018 at 3:32
  • $\begingroup$ For exp(102*log(-1)) Maple gives 1 here is screen shot !Mathematica graphics $\endgroup$
    – Nasser
    Feb 25, 2018 at 4:01
  • $\begingroup$ @Nasser I see an imaginary part on the order of 10^-8 on the floating-point input; that seems like a large error. Does Maple use single-precision? I mean Mathematica gives 1, too: i.stack.imgur.com/IoQZv.png $\endgroup$
    – Michael E2
    Feb 25, 2018 at 4:05
  • $\begingroup$ By default, Maple software floating points uses the Digits setting. By default this is set to 10. Here is the same thing, when I changed it to 16 !Mathematica graphics Maple software floating point is what used by default. Now it give similar value as Mathematica. To use hardware floating point, there is evalfh also. $\endgroup$
    – Nasser
    Feb 25, 2018 at 4:45
8
$\begingroup$

I want to mention that this sum has a closed form in terms of Mathematica functions

(-1)^n*LerchPhi[-1, 1, 1 + n] - Log[2]

As already carefully pointed out by Michael, the (-1)^n part introduces the small imaginary parts when you apply it to real values. If you are interested in a approximate result, the easiest way is to calculate the above term for integers and then taking N.

f[n_Integer] := N[(-1)^n*LerchPhi[-1, 1, 1 + n] - Log[2]]

f[100]
(* -0.688172 *)

However, calculating LerchPhi should be faster when calculated with approximate numbers in the first place. So the other solution is to put the N inside LerchPhi. Therefore, the better alternative if you want to calculate this for large n might be this

f2[n_Integer] := (-1)^n*LerchPhi[-1, 1, 1 + N[n]] - Log[2]

A quick comparison shows, that I can easily calculate 2^20 in half a second

f2[2^20] // AbsoluteTiming
(* {0.508786, -0.693147} *)

while the exact computation of f needs about 300x the time of this

f[2^20] // AbsoluteTiming
(* {147.191, -0.693147} *)

Runtime-wise, nothing will beat NSum if it implicitly contains a more expensive function. Therefore, my last point is to mention that you can easily split your sum into to parts: All positive terms and all negative terms. With this, you get completely rid of the (-1)^n term and no Chop is necessary

nn = 100;
NSum[1/n, {n, 2, nn, 2}] - NSum[1/n, {n, 1, nn - 1, 2}]
(* -0.688172 *)
$\endgroup$
4
  • $\begingroup$ Grouping all the positive terms and then all the negatives is going to have a deleterious effect on the resulting precision. Much better would be to pair terms 1/n - 1/(n+1) and simplify to 1/n/(n+1), and best to sort from smallest to largest (here that means iterate n in decreasing order) $\endgroup$
    – Ben Voigt
    Feb 26, 2018 at 1:00
  • 2
    $\begingroup$ @BenVoigt I see your point but have you actually verified this? In this scenario the values of the separate sums are just too different to introduce a large cancellation of digits. This means, that comparing your sum with the separate sum, only the last 3 binary digits are different and 50 binary digits are equal. Nevertheless, your idea of putting two terms together to get rid of the (-1)^n term is very valuable. $\endgroup$
    – halirutan
    Feb 28, 2018 at 8:51
  • $\begingroup$ In addition, calculating your terms and adding them in reverse order gives a result that differs only in the last digit from the exact value (machine precision). $\endgroup$
    – halirutan
    Feb 28, 2018 at 8:58
  • $\begingroup$ Certainly the magnitude of the improvement will vary depending on how quickly the sequence decays. It could well be only affect the final 3 bits in this case. BTW was that from summing (1/n) - (1/(n+1)) or 1/n/(n+1) ? $\endgroup$
    – Ben Voigt
    Feb 28, 2018 at 16:15

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.