The multiplication of the numerator is subject to overflow.
To avoid this, we can divide the multiplicands by 6 before multiplying them together. We can infer that exactly one of the three is a multiple of 3; similarly, one of the first two must be a multiple of 2. So we need to divide one value by 3, and also divide one value by 2 (this will be the same value, if n
is a multiple of 6):
#include <limits.h>
#include <stdio.h>
#include <errno.h>
unsigned long sum_squares_to(unsigned long n)
{
unsigned long a = n;
unsigned long b = n + 1;
unsigned long c = n + n + 1;
if (c <= n || 1.0 * a * b * c / 6 > ULONG_MAX) {
errno = ERANGE;
return 0;
} else {
errno = 0;
}
/* exactly one of a,b,c is a multiple of 3 */
switch (a % 3) {
case 0:
a /= 3; break;
case 1:
c /= 3; break;
case 2:
b /= 3; break;
}
/* exactly one of a,b is a multiple of 2 */
if (a % 2)
b /= 2;
else
a /= 2;
return a * b * c;
}
int main(void)
{
unsigned int zakres = 20;
unsigned long sum = sum_squares_to(zakres);
if (!sum) {
fprintf(stderr, "Could not sum squares to %u\n", zakres);
return 1;
}
printf("suma kwadratow = %ld\n", sum);
return 0;
}
I've also increased the range to unsigned long int
, which may have a bigger range, depending on your target platform.
This is a good lesson in taking results from pure mathematics and expressing them in a program: real-world mathematical numbers don't have the same limitations on precision and range that computer numbers do, and we often have to adapt our algorithms to work well with their machine representations.
BTW, this approach is probably not acceptable for your homework if it prescribes that you must use a loop for the calculation, but it is a valuable learning opportunity, so it's good that you explore this other approach and discover something your teacher hasn't put in front of you; I find that the most effective way to learn, and perhaps you do too. Happy programming!