Avoid using namespace std
. It doesn't even save any typing in this program.
serialNumber
doesn't need to be global.
Consider using unsigned types for numbers when negatives can't be present.
Whilst there's nothing wrong with the factorial
function (and I certainly wouldn't recommend making it recursive), we can skip the i==1
iteration:
constexpr unsigned int factorial(unsigned int n)
{
unsigned int k = 1;
for (unsigned int i = 2u; i <= n; ++i) {
k *= i;
}
return k;
}
Note that we need to be very careful with our inputs to avoid overflow here. With a 16-bit int
, we can compute factorials only up to 8!, and with 32-bit int
, a maximum of 12!. Consider throwing a std::range_error
when the output is too large to represent:
#include <limits>
#include <stdexcept>
constexpr unsigned int factorial(unsigned int n)
{
unsigned int k = 1;
for (unsigned int i = 2u; i <= n; ++i) {
if (k >= std::numeric_limits<decltype(k)>::max() / n) {
throw std::range_error("factorial");
}
k *= i;
}
return k;
}
Reduce scope of variables, and keep the names of related variables obviously connected; i.e. instead of using numbers for the factorials, include a
, b
or c
in their names (e.g. fa
, fb
, fc
).
We can reduce the search space by limiting the loops so that we don't repeat tests so much (given that both operations are commutative):
for (unsigned a = 1; a < 11; ++a)
{
auto const fa = factorial(a);
for (unsigned b = 1; b <= a; ++b)
{
auto const fb = factorial(b);
for (unsigned c = 1; c <= b; ++c)
{
auto const fc = factorial(c);
Notice how the inner loops reach but don't exceed the current value of the containing loop.
Prefer '\n'
to std::endl
when there's no need to flush the output immediately (in fact, when a newline and flush are both needed, I prefer to write << '\n' << std::flush
to be absolutely clear what we want).
Modified code
#include <iostream>
#include <limits>
#include <stdexcept>
constexpr unsigned int factorial(unsigned int n)
{
unsigned int k = 1;
for (unsigned int i = 2u; i <= n; ++i) {
if (k >= std::numeric_limits<decltype(k)>::max() / n) {
throw std::range_error("factorial");
}
k *= i;
}
return k;
}
int main()
{
for (unsigned a = 1; a < 11; ++a) {
auto const fa = factorial(a);
for (unsigned b = 1; b <= a; ++b) {
auto const fb = factorial(b);
for (unsigned c = 1; c <= b; ++c) {
auto const fc = factorial(c);
if (fa + fb + fc == a * b * c) {
std::cout << "Pass:" << " "
<< a << " & " << b << " & " << c
<< '\n';
}
}
}
}
}
Exercise
What would you change to extend this to search for N numbers whose product equals the sum of their factorials, when N is given at run time?