/*
 * Find and display the minimum sum of the squares for integers.
 *
 * Copyright (C) 2007 George Gesslein II.
 */

/*
 * Usage: matho-sumsq [numbers]
 *
 * This program finds the minimum number of positive integers squared
 * and summed to equal a given positive integer.  If the number of squared
 * integers is 2, all combinations with 2 squares are displayed,
 * otherwise only the first solution found is displayed.
 *
 * If nothing is specified on the command line, the program starts at 0 and
 * counts up.
 *
 * This file is mostly useful for testing the long integer square root function lsqrt() in file "lsqrt.c".
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>

#define	true	1
#define	false	0

#define	squared(a)	((a) * (a))

long	squares[4];

long	lsqrt(long y);

/*
 * Find the sum of "n" squares that equal "d1" and display if found.
 *
 * Return false if not found.
 */
int
sumsq(long d1, int n)
{
	int	i = 0;
	long	d2;
	long	save = 0;
	int	found_one = false;

	d2 = d1;
try_again:
	for (;;) {
		if (i == 2) {
			save = d2;
		}
		squares[i] = lsqrt(d2);
		if (squares[i] < 0) {
			exit(1);
		}
		d2 -= squared(squares[i]);
		i++;
		if (i >= n) {
			break;
		}
	}
	if (d2 == 0) {
		for (i = 0; i < n; i++) {
			d2 += squared(squares[i]);
		}
		if (d2 != d1) {
			fprintf(stderr, "Result doesn't compare identical to original number!\n");
			exit(1);
		}
		for (i = 0; i < (n - 1); i++) {
			if (squares[i] < squares[i+1]) {
				goto skip_print;
			}
		}
		found_one = true;
		printf("%ld = %ld^2", d1, squares[0]);
		for (i = 1; i < n; i++) {
			if (squares[i] != 0)
				printf(" + %ld^2", squares[i]);
		}
		printf("\n");
skip_print:
		if (!found_one) {
			fprintf(stderr, "Found bug!\n");
			exit(1);
		}
		if (n != 2) {
			return found_one;
		}
	}
	switch (n) {
	case 4:
		if (squares[2] > squares[n-1]) {
			squares[2] -= 1;
			d2 = save - squared(squares[2]);
			i = 3;
			goto try_again;
		}
	case 3:
		if (squares[1] > squares[n-1]) {
			squares[1] -= 1;
			d2 = d1 - squared(squares[0]) - squared(squares[1]);
			i = 2;
			goto try_again;
		}
	case 2:
		if (squares[0] > squares[n-1]) {
			squares[0] -= 1;
			d2 = d1 - squared(squares[0]);
			i = 1;
			goto try_again;
		}
	}
	return found_one;
}

/*
 * Display the shortest sum of the squares for long integer "d1".
 *
 * Return number of squares.
 */
int
findsq(long d1)
{
	if (sumsq(d1, 1))
		return 1;
	if (sumsq(d1, 2))
		return 2;
	if (sumsq(d1, 3))
		return 3;
	if (!sumsq(d1, 4)) {
		fprintf(stderr, "Whoops!  Can't find the sum of four squares that equal %ld.\n", d1);
		exit(1);
	}
	return 4;
}

int
main(int argc, char *argv[])
{
	int	i;
	long	d1 = 0;
	char	*cp;

	if (argc > 1) {
		for (i = 1; i < argc; i++) {
			errno = 0;
			d1 = strtol(argv[i], &cp, 10);
			if (errno || d1 <= 0) {
				fprintf(stderr, "Invalid number.\n");
				exit(1);
			}
			findsq(d1);
		}
	} else {
		for (;; d1 += 1) {
			findsq(d1);
		}
	}
	exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1