# Sums and products


SetHelp ("SumProductTolerance", "parameters", "Tolerance for InfiniteSum and InfiniteProduct")
parameter SumProductTolerance=10.0^(-5);
SetHelp ("SumProductSFS", "parameters", "How many successive steps to be within tolerance for InfiniteSum and InfiniteProduct")
parameter SumProductSFS=20;
SetHelp ("SumProductNumberOfTries", "parameters", "How many iterations to try for InfiniteSum and InfiniteProduct")
parameter SumProductNumberOfTries=10000;

#calculate an infinite sum until the new terms stop making a difference
SetHelp("InfiniteSum","calculus","Try to calculate an infinite sum for a single parameter function");
function InfiniteSum (func, start, inc) = (
	local *;
	if not IsValue(start) or not IsValue(inc) then
		(error("InfiniteSum: start,inc arguments not values");bailout)
	else if not IsFunction(func) then
		(error("InfiniteSum: func argument not a function");bailout);
	wt = 0;
	oldsum = 0.0;
	for n = 1 to SumProductNumberOfTries do (
		newsum = oldsum + func(start);
		if |newsum-oldsum| < SumProductTolerance then (
			increment wt;
			if wt >= SumProductSFS then (
				return newsum
			)
		) else (
			wt = 0
		);
		oldsum = newsum;
		start = start + inc
	);
	null
);

#calculate an infinite sum until the new terms stop making a difference
SetHelp("InfiniteSum2","calculus","Try to calculate an infinite sum for a double parameter function with func(arg,n)");
function InfiniteSum2(func,arg,start,inc) = (
	local *;
	if not IsValue(start) or not IsValue(inc) then
		(error("InfiniteSum2: start,inc arguments not values");bailout)
	else if not IsFunction(func) then
		(error("InfiniteSum2: func argument not a function");bailout);
	wt = 0;
	oldsum = 0.0;
	for n = 1 to SumProductNumberOfTries do (
		newsum = oldsum + func(arg,start);
		if |newsum-oldsum| < SumProductTolerance then (
			increment wt;
			if wt >= SumProductSFS then (
				return newsum
			)
		) else (
			wt = 0
		);
		oldsum = newsum;
		start = start + inc
	);
	null
);

#calculate an infinite product until the new terms stop making a difference
SetHelp("InfiniteProduct","calculus","Try to calculate an infinite product for a single parameter function");
function InfiniteProduct (func, start, inc) = (
	local *;
	if not IsValue(start) or not IsValue(inc) then
		(error("InfiniteProduct: start,inc arguments not values");bailout)
	else if not IsFunction(func) then
		(error("InfiniteProduct: func argument not a function");bailout);
	wt = 0;
	oldprod = 1.0;
	for n = 1 to SumProductNumberOfTries do (
		newprod = oldprod * func(start);
		if |newprod-oldprod| < SumProductTolerance then (
			increment wt;
			if wt >= SumProductSFS then (
				return newprod
			)
		) else (
			wt = 0
		);
		oldprod = newprod;
		start = start + inc
	);
	null
);

#calculate an infinite product until the new terms stop making a difference
SetHelp("InfiniteProduct2","calculus","Try to calculate an infinite product for a double parameter function with func(arg,n)");
function InfiniteProduct2(func,arg,start,inc) = (
	local *;
	if not IsValue(start) or not IsValue(inc) then
		(error("InfiniteProduct2: start,inc arguments not values");bailout)
	else if not IsFunction(func) then
		(error("InfiniteProduct2: func argument not a function");bailout);
	wt = 0;
	oldprod = 1.0;
	for n = 1 to SumProductNumberOfTries do (
		newprod = oldprod * func(arg,start);
		if |newprod-oldprod| < SumProductTolerance then (
			increment wt;
			if wt >= SumProductSFS then (
				return newprod
			)
		) else (
			wt = 0
		);
		oldprod = newprod;
		start = start + inc
	);
	null
);

