use 5.010;
use strict;
use warnings;
use bigint;

sub leftfact {
	my ($n) = @_;
	state $cached = 0;
	state $factorial = 1;
	state $leftfact = 0;
	if( $n < $cached ) {
		($cached, $factorial, $leftfact) = (0, 1, 0);
	}
	while( $n > $cached ) {
		$leftfact += $factorial;
		$factorial *= ++$cached;
	}
	return $leftfact;
}

printf "!%d =%s\n", $_, leftfact($_) for 0 .. 10, map $_*10, 2..11;
printf "!%d has%d digits.\n", $_, length leftfact($_) for map $_*1000, 1..10;