Hello all. I'm new to Perl, and really new to programming in general - I'm an sysadmin by trade (please don't hold that against me). Inspired by the Hanoi towers node, I wrote this as an learning exercise on recursive subroutines.

It's really a simple function, it prompts you for n, and then calculates (x + y)^n and expands it out as you would in an algebra 101 class, using binomial theorem. I welcome any comments, suggestions or opinions. I'd like to know if there's a better way to format the output other than running it through a bunch of regex's. I know it's not the prettiest code, but bear with me:

#!/usr/bin/perl use strict; use warnings; my ($power, $result); sub binomial_power { my ($c, $xp, $yp) = @_; $result .= $c . "x^" . $xp . "y^" . ($yp - 1) . " + "; if ($yp <= $power ) { binomial_power ((($c * $xp)/$yp), ($xp-1), ( +$yp+1));} } # Get the input print "\nEnter the power: "; chomp($power = (<STDIN>)); # Do the work binomial_power (1, $power, 1); # Make it pretty $result =~ s/1x/x/g; $result =~ s/x\^1/x/g; $result =~ s/y\^1/y/g; $result =~ s/x\^0//g; $result =~ s/y\^0//g; # And print it out print "The result is: \n(x + y)^$power = $result\n";

For reference - $c is the coefficient, $xp is the exponent of x, and $yp is the exponent of y

Replies are listed 'Best First'.
Re: Algebraic Expansion of Binomials Using a Recursive Subroutine
by toolic (Bishop) on Jul 28, 2011 at 14:39 UTC
    I have refactored your code:
    • no global variables are used by your function
    • all formatting is done within the function
    • you no longer get a trailing plus sign (+)
    • added check on input
    use warnings; use strict; # Get the input print "\nEnter the power: "; chomp(my $power = (<STDIN>)); if (($power =~ /\D/) or ($power == 0) or ($power > 9)) { die "Error: $power is not a positive integer less than 10"; } # Do the work my $result = binomial_power(1, $power, 1); # And print it out print "The result is: \n(x + y)^$power = $result\n"; sub binomial_power { my ($c, $xp, $yp) = @_; my $result = $c . "x^" . $xp . "y^" . ($yp - 1); $result =~ s/1x/x/g; $result =~ s/([xy])\^1/$1/g; $result =~ s/[xy]\^0//g; if ($xp > 0) { $result . " + " . binomial_power((($c * $xp)/$yp), ($xp-1), ($ +yp+1)); } else { return $result; } }
    While I haven't eliminated the formatting regexes, I have combined a couple of them.

    Please fix the spelling of "Binomals" in your title; it will help others find your code when searching.

    UPDATE: changed input checking to reject power > 9, since our code does not support it.

      More refactoring…

      #!/usr/bin/perl use strict; use warnings; # Get the input... print "\nEnter the power (a positive integer from 1 through 33): "; chomp(my $power = (<STDIN>)); # Quietly end if there's no input... $power =~ m/\S/ or exit 1; # Validate the input... $power =~ m/^(?:[1-9]|[12][0-9]|3[0-3])$/ or die "$power is not a positive integer from 1 through 33\n"; # Expand the binomial... my $expansion = binomial_expansion(1, $power, 1); # ...and then print the result... print "(x + y)^$power = $expansion\n"; exit 0; sub binomial_expansion { my ($k, $x, $y) = @_; my $term = sprintf "%dx^%dy^%d", $k, $x, ($y - 1); $term =~ s/\b1(?=x)//; # Remove 1 from 1x $term =~ s/(?<=[xy])\^1(?!\d)//g; # Remove ^1 from x^1 and y^1 $term =~ s/[xy]\^0//; # Remove x^0 and y^0 return $x > 0 ? sprintf "%s + %s", $term, binomial_expansion(($k * $x) / $y, ($x - 1), ($y + 1)) : $term ; }

      Refactoring your refactoring just a tad…

      # Get the input... print "\nEnter the power (a positive integer from 1 through 9): "; chomp(my $power = (<STDIN>)); # Quietly end if there's no input... $power =~ m/\S/ or exit 1; # Validate the input... $power =~ m/^[1-9]$/ or die "$power is not a positive integer from 1 through 9\n";
Re: Algebraic Expansion of Binomials Using a Recursive Subroutine
by ambrus (Abbot) on Jul 29, 2011 at 12:25 UTC

    The string substitions you are doing are incorrect. If you choose n = 14, then instead of + 1001x^10y^4<c> it prints <c>+ 100x0y^4. Further, the program prints an extra plus sign at the very end of the expression.

    Update: the \b regex anchor gives an easy way to fix these bugs in the substitutions.