It looks like this question has gotten enough interest that it deserves a complete answer on how to do it using MATLAB. And since you have done something reasonable...
You simply cannot compute factorial of a number as a double, if n is greater than 18.
factorial(1:20) < flintmax
ans =
1×20 logical array
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0
Actually, it looks like you might get to 20, if you use uint64. But uint64 overflows beyond that point. So using a double will just fail for the sum of digits of factorial(100).
factorial(100)
ans =
9.3326e+157
That is WAY past flintmax. Personally, I'd do it elegantly as:
sum(char(factorial(sym(100))) - '0')
ans =
648
However nothing stops you from doing the multiplication the hard way, using carries.
factdigs = zeros(1,200);
factdigs(end) = 1;
N = 100;
for n = 2:N
factdigs = factdigs * n;
carry = 1;
while any(carry)
R = rem(factdigs,10);
carry = (factdigs - R)/10;
factdigs = R + [carry(2:end),0];
end
end
sum(factdigs)
ans =
648
This will work as long as I make the vector of digits long enough that factorial(100) does not overflow a 200 digit number. And since we know that factorial(100) is on the order of 9e157, 200 digits is fine.
reshape(factdigs,10,20)'
ans =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 9 3 3 2 6 2 1 5
4 4 3 9 4 4 1 5 2 6
8 1 6 9 9 2 3 8 8 5
6 2 6 6 7 0 0 4 9 0
7 1 5 9 6 8 2 6 4 3
8 1 6 2 1 4 6 8 5 9
2 9 6 3 8 9 5 2 1 7
5 9 9 9 9 3 2 2 9 9
1 5 6 0 8 9 4 1 4 6
3 9 7 6 1 5 6 5 1 8
2 8 6 2 5 3 6 9 7 9
2 0 8 2 7 2 2 3 7 5
8 2 5 1 1 8 5 2 1 0
9 1 6 8 6 4 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Of course, the code as I wote it would fail around n = 122.
factorial(122)
ans =
9.875e+202
That would be fixable merely by preallocating factdigs to be a longer vector. Or, with a little more care in the code, I could have written it to dynamically expand the vector of digits, so factorials of any size would then theoretically work.
Best Answer