I've defined a function that computes the sum of the base-b digits of n:
DigitSum[n_, b_] := Total[IntegerDigits[n, b]]
Then I defined a function that computes the sum of the base-b digits of all of the integers up to x:
CumDigitSum[x_, b_] := Sum[DigitSum[n, b], {n, 1, x}]
Using these functions, I get
CumDigitSum[1000000,10]=27000001
which is correct. But then for larger inputs I get nonsense like
CumDigitSum[1000001,10]=500011500011
If I work in a different base, the same thing happens: at exactly 1000001, Mathematica begins computing the sum incorrectly. If I bypass my user-defined functions and just write what I mean, I get the correct answer:
Sum[Total[IntegerDigits[n, 10]], {n, 1, 1000001}] = 27000003
Any idea what could be happening here?
Answer
If you wish to compute the correct values using the method you have chosen you could specify Method -> "Procedural"
for Sum
:
CumDigitSum[x_, b_] := Sum[DigitSum[n, b], {n, 1, x}, Method -> "Procedural"]
CumDigitSum[1000001, 10]
27000003
However, the problem comes form the fact that Sum
attempts to speed the calculation by finding a symbolic equivalent. Let's see what your DigitSum
returns with symbolic input:
DigitSum[n, b]
b + n
That's clearly not correct generally! Why does this happen? Mathematica functions often work on arbitrary expressions as well as lists, and that is the case with Total
. First the IntegerDigits
call remain unevaluated:
IntegerDigits[n, b]
IntegerDigits[n, b]
But then Total
adds its arguments as though this were {n, b}
:
IntegerDigits[n, b] // Total
b + n
To prevent this you can add a Condition
or PatternTest
as belisarius recommended in a comment above:
DigitSum[n_?NumericQ, b_] := Total[IntegerDigits[n, b]]
This will block Sum
form finding a (false) symbolic equivalent thereby forcing it to use a procedural evaluation, even with your original CumDigitSum
definition.
For this particular case it is somewhat cleaner to use Tr
in place of Total
as it will not sum the arguments of an arbitrary expression:
Tr[IntegerDigits[n, b]]
Tr[IntegerDigits[n, b]]
Therefore:
DigitSum[n_, b_] := Tr[IntegerDigits[n, b]]
By the way, it is not recommended to start user Symbol names with capital letters as these can conflict with built-in functions, now or later.
Comments
Post a Comment