#!/usr/bin/perl

# difference.pl
# Jan 4, 2005
# Noam Sturmwind
#
# Calculate finite differences of a function
# (see http://mathworld.wolfram.com/FiniteDifference.html)
#
# This code is public domain. Use it as you like.

# CHANGES
# Jan. 20, 2005		Added the print_zero_rows option.

### Change these parameters ###

# The number of terms to print in the first row
$numterms = 8;

# The function to calculate
$function = '$x**3';

# Should we print lines that are all zeros, to complete the triangle?
# Or should we stop with the last line containing non-zero values?
# 1 (True) or 0 (False)
$print_zero_rows = 0;

##########################################

# The multiple of spaces printed at the beginning of rows.
# Play with this if you change the printf formatting below and things don't
# line up in a nice inverted triangle (or trapezoid, depends on the setting
# of print_zero_rows above) when output is printed.
$spaces = 5;

sub sprintfdecimal($) {
	# A clunky workaround for printf limitations (or my limited
	# understanding of printf formatting).
	# If the number has non-zero decimals, print two decimal places.
	# Otherwise, don't print them.

	my $numtermsumber = shift;
	if (substr(sprintf("%8.2f", $numtermsumber), -2, 2) eq "00") {
		return sprintf("%8.0f", $numtermsumber);
	} else {
		return sprintf("%8.2f", $numtermsumber);
	}
}

sub f($) {
	my $x = shift;
	return eval($function);
}

# Create the sequence
for ($x = 1; $x <= $numterms; $x++) {
	push @seq, sprintfdecimal(f($x));
}
@row = @seq;

$" = "  ";
print "@seq\n";

# Do the subtractions for each successive row
for ($rownum = 2; $rownum <= $numterms; $rownum++) {
	@prevrow = @row;
	@row = ();
	for ($termnum = 1; $termnum <= $numterms - $rownum + 1; $termnum++) {
		push @row, sprintfdecimal($prevrow[$termnum] - $prevrow[$termnum-1]);
	}
	print ' 'x(($rownum-1)*$spaces) . "@row\n" if ($print_zero_rows or "@row" !~ /^[\s0]*$/);
}
