Tim Varley Logo
Tim Varley Principal AI Engineer and Tech Leader
Problem #20 medium

Factorial Digit Sum

n!n! means n×(n1)××3×2×1n \times (n - 1) \times \cdots \times 3 \times 2 \times 1.

For example, 10!=10×9××3×2×1=362880010! = 10 \times 9 \times \cdots \times 3 \times 2 \times 1 = 3628800, and the sum of the digits in the number 10!10! is 3+6+2+8+8+0+0=273 + 6 + 2 + 8 + 8 + 0 + 0 = 27.

Find the sum of the digits in the number 100!100!.

View on Project Euler

Implementations

cpp
// Answer: 648
#include <iostream>
#include <chrono>
static const int big_size = 500;
int factorial_digit_sum(int fme)
{
int digits[big_size] = {0};
digits[0] =1;
int sum = 0;
for (size_t factor = 2; factor < fme; factor++) {
int carry = 0;
for (size_t j = 0; j < big_size; j++) {
int x = digits[j] * factor + carry;
carry = 0;
sum = x;
if( x > 9){
sum = x % 10;
carry = x / 10;
}
digits[j]=sum;
}
}
int ret = 0;
for (size_t i = 0; i < big_size; i++) {
ret += digits[i];
}
return ret;
}
int factorial_digit_sum_opt(int fme)
{
int digits[big_size] = {0};
digits[0] =1;
int sum = 0;
int high_water = 2;
for (size_t factor = 2; factor < fme; factor++) {
int carry = 0;
for (size_t j = 0; j <= high_water; j++) {
int x = digits[j] * factor + carry;
carry = 0;
sum = x;
if( x > 9){
sum = x % 10;
carry = x / 10;
if( j == high_water ){
high_water+=2;
}
}
digits[j]=sum;
}
}
int ret = 0;
for (size_t i = 0; i < high_water; i++) {
ret += digits[i];
}
return ret;
}
#if ! defined UNITTEST_MODE
int main(int argc, char const *argv[])
{
typedef std::chrono::high_resolution_clock my_clock;
typedef std::chrono::milliseconds timer_res;
uint64_t a,b;
auto p1 = my_clock::now();
for( int i = 0 ; i < 1000; i++ ){
a = factorial_digit_sum(100);
}
auto p2 = my_clock::now();
auto a1 = p2-p1;
std::cout << "Brute force took: " << a1.count() << std::endl;
p1 = my_clock::now();
for( int i = 0 ; i < 1000; i++ ){
b = factorial_digit_sum_opt(100);
}
p2 = my_clock::now();
a1 = p2-p1;
std::cout << "Opt force took: " << a1.count() << std::endl;
std::cout << "Answer: " << factorial_digit_sum_opt(100) << std::endl;
}
#endif // #if ! defined UNITTEST_MODE
View on GitHub
O(n) time complexity

Solution Notes

Mathematical Background

This problem involves computing the factorial of 100 (100!100!) and summing its digits. Factorials grow extremely rapidly - 100!100! has 158 digits and is approximately 9.33×101579.33 \times 10^{157}.

The number of digits in n!n! can be estimated using Stirling’s approximation: ln(n!)nlnnn+12ln(2πn)\ln(n!) \approx n\ln n - n + \frac{1}{2}\ln(2\pi n)

For n=100n = 100, this gives approximately 157.97 digits, matching the actual result.

Algorithm Analysis

Big integer factorial computation: Most implementations use arbitrary-precision arithmetic since 100!100! exceeds standard integer types.

Approaches:

  • Array-based multiplication: Store the result as an array of digits, multiplying digit-by-digit with carry propagation
  • Big integer libraries: Languages with built-in big integer support (Python, Java) can compute factorial directly
  • Iterative multiplication: Start with 1, multiply by each integer from 2 to 100

Digit summation: Convert the final number to a string or iterate through digit array, summing each digit.

Time complexity is O(n²) due to the growing number size with each multiplication. Space complexity is O(d) where d ≈ 158 is the number of digits.

Key Insights

  • 100!100! has 158 digits and digit sum of 648
  • Standard integer types cannot hold such large numbers
  • The algorithm scales well for larger factorials using the same digit-array approach
  • Most digits are zeros due to the factorial’s many trailing zeros (24 zeros in 100!100!)
  • This demonstrates the factorial function’s explosive growth
  • Practical applications include probability calculations and combinatorics

Educational Value

This problem teaches:

  • Factorial computation and its mathematical properties
  • Arbitrary-precision arithmetic implementation
  • The limitations of built-in numeric types
  • Digit manipulation and summation algorithms
  • Handling very large numbers in constrained environments
  • The relationship between mathematical growth and computational complexity
  • When to use custom algorithms versus built-in libraries