# Solver Linear Equation Solver

Algebra ->  Equations -> Solver Linear Equation Solver      Log On

### Source code of 'Linear Equation Solver'

This Solver (Linear Equation Solver) was created by by jim_thompson5910(33401)  : View Source, Show, Put on YOUR site
About jim_thompson5910: If you need more math help, then you can email me. I charge \$2 for steps, or \$1 for answers only. Email: jim_thompson5910@hotmail.com Website: http://www.freewebs.com/jimthompson5910/home.html

 ==section input This solver will show you, step-by-step, how to solve linear equations with one variable. Solve the equation *[input 50 equation=3x+5=2x-11] for the variable *[input var=x] Note: There are so many ways to enter the equation that it is impossible to check all of the bad possible inputs. So make sure that you've entered the equation correctly. Also, be sure to check the answer (as this solver isn't perfect). Further note: Someone pointed out that a simple equation like -(x+3)=9 generates the wrong answer. This is because of the negative outside and my solver isn't trained to look for things of this nature. So be sure to throw in a 1 to get -1(x+3)=9 to make it work correctly. ==section solution perl ## linear equation solver (solve for any var) ## input #chomp(my \$input=<>); #my (\$equation,\$var)=split(/,/,\$input); my \$show=1; #used if you want to cover up beginning and end of print statements in solver my \$ans=linear_equation_solver(\$equation,\$var,\$show,1); ## sort numbers in ascending order sub my_number_sort { my @array=@_; for (my \$i=0;\$i<@array;\$i++) { for (my \$j=0;\$j<@array;\$j++) { if(\$array[\$i]<\$array[\$j] and \$i!=\$j) { #print " ",join(",",@array),"\n"; my \$temp=\$array[\$i]; \$array[\$i]=\$array[\$j]; \$array[\$j]=\$temp; } } } return @array; } ## sort characters in ascending order sub my_char_sort { my @array=@_; for (my \$i=0;\$i<@array;\$i++) { for (my \$j=0;\$j<@array;\$j++) { if(\$array[\$i] le \$array[\$j] and \$i!=\$j) { #print " ",join(",",@array),"\n"; my \$temp=\$array[\$i]; \$array[\$i]=\$array[\$j]; \$array[\$j]=\$temp; } } } return @array; } #extract coefficients from multivariate polynomial. Coefficients collected in order they appear #eg x+2y-1/3z ---> 1, 2, -1/3 sub multivariate_coefficient { my \$expression=\$_[0]; #my \$degree=\$1 if \$expression=~m/\^(\d+)/; \$expression=~s/\s//g; \$expression=~s/\-/\+\-/g; # change each - into +- \$expression=~s/^\+//; # remove first + \$expression=~s/([a-z])(\+|\-)/\$1\^1\$2/g; # replace 5x with 5x^1 \$expression=~s/([a-z])\$/\$1\^1/g; # replace 5x with 5x^1 \$expression=~s/(\+|\-)([a-z])/\$1 1 \$2/g; # replace +x with +1x \$expression=~s/(^|=)([a-z])/\$1 1 \$2/g; # replace +x with +1x \$expression=~s/\s//g; # remove spaces #print "SUB multivariate_coefficient: \$expression\n"; \$expression=~s/\s//g; my @terms=split(/\+/,\$expression); my @coefficients; for(my \$i=0;\$i<@terms;\$i++) { push(@coefficients,\$1) if \$terms[\$i]=~m/^(.*?)[a-z]/; push(@coefficients,\$terms[\$i]) if \$terms[\$i]!~m/[a-z]/; } #@coefficients=map{s/^\-\$/\-1/g;\$_} @coefficients; @coefficients=map{s/\^1\$//g;\$_} @coefficients; return @coefficients; } sub generate_terms { my \$expression=\$_[0]; #my \$degree=\$1 if \$expression=~m/\^(\d+)/; \$expression=~s/\s//g; \$expression=~s/\-/\+\-/g; # change each - into +- \$expression=~s/^\+//; # remove first + \$expression=~s/\(\+/\(/g; # replace (+ with ( #\$expression=~s/([a-z])(\+|\-)/\$1\^1\$2/g; # replace 5x with 5x^1 #\$expression=~s/([a-z])\$/\$1\^1/g; # replace 5x with 5x^1 \$expression=~s/(\+|\-)([a-z])/\$1 1 \$2/g; # replace +x with +1x \$expression=~s/^([a-z])/1 \$1/g; # replace +x with +1x \$expression=~s/\++/\+/g; \$expression=~s/\s//g; #print "

MODULE GENERATE TERMS: \$expression

"; my @terms=split(/\+/,\$expression); return @terms; } sub gcf { my (\$x, \$y) = @_; (\$x, \$y) = (\$y, \$x % \$y) while \$y; return \$x; } sub lcm { return(\$_[0] * \$_[1] / gcf(\$_[0], \$_[1])); } sub multigcf { my \$x = shift; \$x = gcf(\$x, shift) while @_; return \$x; } sub multilcm { my \$x = shift; \$x = lcm(\$x, shift) while @_; return \$x; } # find and extract monomial coefficient .... NEW sub monomial_coefficient { my \$exp=\$_[0]; my \$coefficient; if(\$exp=~m/[a-z]/) { \$coefficient=-1 if \$exp=~m/^\-/; \$coefficient="\$1" if \$exp=~m/^(\-?\d+\/\d+|\-?\d+\.\d+|\-?\d+)[a-z]/; \$coefficient=1 unless \$coefficient; } else {\$coefficient=\$exp;} #print "Coefficient for \$exp is : \$coefficient\n"; return \$coefficient; } sub rewrite_fraction { my \$exp=\$_[0]; \$exp=~s/\(|\)//g; my \$coefficient=monomial_coefficient(\$exp); #my \$var=\$1 if \$exp=~m/ my \$temp=\$exp; \$temp=~s/^\$coefficient// if \$coefficient; if(\$exp=~m/\/(\-?\d+)/) {\$coefficient.="/\$1" if \$coefficient!~m/\//; \$temp=~s/\/(\-?\d+)//;} \$temp=~s/^\-//; my \$ans="(\$coefficient)\$temp"; \$ans=~s/\((\-?\d+\.\d+|\-?\d+)\)/\$1/; \$ans=~s/^1([a-z])/\$1/; #print "\$coefficient \$exp = \$ans\n"; return \$ans; } #rewrite_fraction("(5/3)xz^2y"); #my \$exp="-10"; #my \$ans=monomial_coefficient(\$exp); #print "

ANS: \$ans

"; # find and extract monomial exponents sub monomial_exponent { my \$exp=\$_[0]; my \$exponent_hash_ref; my %hash; for my \$i ('a'..'z') { if(\$exp=~m/\$i/) {#print "i=\$i\n"; \$exponent_hash_ref->{\$i}=\$1 if \$exp=~m/\$i\^\(?(\-?\d+)\)?/; #\$exponent_hash_ref->{\$i}=1 if \$exp=~m/\$i(\w+|\)|\$)/; \$exponent_hash_ref->{\$i}=1 if \$exp!~m/\$i\^/; #\$hash{\$i}=\$1 if \$exp=~m/\$i\^(\d+)/; #\$hash{\$i}=1 if \$exp=~m/\$i[^\^]/; } } #print "EXP123: \$exponent_hash_ref->{'y'}"; return \$exponent_hash_ref; } #my \$exp1="5x^15"; #my \$ans2=monomial_exponent(\$exp1); #my %temp=%\$ans2; #print "

ANS: \$ans2->{'x'}

"; #input format: 2 strings of arguments and print argument sub monomial_multiplication { die "Needs 3 arguments " if @_!=3; my \$print=pop; my @monomials=@_; my \$final_coefficient; # extract coefficients my \$coefficient1=monomial_coefficient(\$monomials[0]); my \$coefficient2=monomial_coefficient(\$monomials[1]); # multiply coefficients if((\$coefficient1!~m/\./)&&(\$coefficient2!~m/\./)) {\$final_coefficient=reduce(rat(\$coefficient1,\$coefficient2,"*"));} else {\$final_coefficient=\$coefficient1*\$coefficient2;} # extract exponents my \$exp_hash_ref1=monomial_exponent(\$monomials[0]); my \$exp_hash_ref2=monomial_exponent(\$monomials[1]); my (\$final_exp_hash_ref,\$final_var); my @temp_monomials=@monomials; @temp_monomials=map{s/^\-?\d+\.\d+|^\-?\d+//;\$_} @temp_monomials; my \$display="\$final_coefficient@temp_monomials"; \$display=~s/(\d+)\/(\d+)/\(\$1\/\$2\)/g; print "

{{{\$final_coefficient@temp_monomials}}} Multiply the coefficients {{{\$coefficient1}}} and {{{\$coefficient2}}} to get {{{\$final_coefficient}}}

" if \$print==1; #if monomials DONT contain a variable if((\$monomials[0]!~m/[a-z]/)&&(\$monomials[1]!~m/[a-z]/)) { return \$final_coefficient; } my (\$int_exp_hash,\$intermediate); # add exponents for my \$i ('a'..'z') { unless(exists \$exp_hash_ref1->{\$i}) {\$exp_hash_ref1->{\$i}=0;} unless(exists \$exp_hash_ref2->{\$i}) {\$exp_hash_ref2->{\$i}=0;} \$final_exp_hash_ref->{\$i}=\$exp_hash_ref1->{\$i}+\$exp_hash_ref2->{\$i}; if((\$exp_hash_ref1->{\$i}!=0)&&(\$exp_hash_ref2->{\$i}!=0)) { \$int_exp_hash->{\$i}="\$i^(\$exp_hash_ref1->{\$i}+\$exp_hash_ref2->{\$i})"; #print "i=\$i \$i^(\$exp_hash_ref1->{\$i}+\$exp_hash_ref2->{\$i})\n"; \$intermediate.=\$int_exp_hash->{\$i}; } # else # { \$final_var.="\$i^\$final_exp_hash_ref->{\$i}" if \$final_exp_hash_ref->{\$i}!=0; \$final_var=~s/\^1\$// if(\$final_var); } if((\$monomials[0]=~m/[a-z]/)&&(\$monomials[1]=~m/[a-z]/)) { \$display="\$final_coefficient\$intermediate"; \$display=~s/(\d+)\/(\d+)/\(\$1\/\$2\)/g; print "

{{{\$display}}} When you multiply monomials, simply add the exponents.

" if \$print==1; } \$final_var="" unless(\$final_var); \$final_coefficient=1 unless(\$final_coefficient); my \$ans="\$final_coefficient\$final_var"; \$ans=~s/^1([a-z])/\$1/g; if((\$monomials[0]=~m/[a-z]/)&&(\$monomials[1]=~m/[a-z]/)) {print "

" if \$print==1;} ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return (\$final_coefficient,\$final_var) if ( wantarray ); #-- neither undefined nor list context, return scalar return \$ans; } #my @exp=qw(1 xy); #my \$ans1=monomial_multiplication(@exp,1); #print "

(\$exp[0])*(\$exp[1])=\$ans1

"; #input format: 2 strings of arguments and print argument sub monomial_division { die "Needs 3 arguments " if @_!=3; my \$print=pop; my @monomials=@_; my \$final_coefficient; # extract coefficients my \$coefficient1=monomial_coefficient(\$monomials[0]); my \$coefficient2=monomial_coefficient(\$monomials[1]); # divide coefficients if((\$coefficient1!~m/\./)&&(\$coefficient2!~m/\./)) {\$final_coefficient=reduce(rat(\$coefficient1,\$coefficient2,"/"));} else {\$final_coefficient=\$coefficient1/\$coefficient2;} # extract exponents my \$exp_hash_ref1=monomial_exponent(\$monomials[0]); my \$exp_hash_ref2=monomial_exponent(\$monomials[1]); my (\$final_exp_hash_ref,\$final_var); my @temp_monomials=@monomials; @temp_monomials=map{s/^\-?\d+//;\$_} @temp_monomials; my \$display="\$final_coefficient@temp_monomials"; \$display=~s/(\d+)\/(\d+)/\(\$1\/\$2\)/g; print "

{{{\$display}}} Divide the coefficients {{{\$coefficient1}}} and {{{\$coefficient2}}} to get {{{\$final_coefficient}}}

" if \$print==1; #if monomials DONT contain a variable if((\$monomials[0]!~m/[a-z]/)&&(\$monomials[1]!~m/[a-z]/)) { return \$final_coefficient; } my (\$int_exp_hash,\$intermediate); # subtract exponents for my \$i ('a'..'z') { unless(exists \$exp_hash_ref1->{\$i}) {\$exp_hash_ref1->{\$i}=0;} unless(exists \$exp_hash_ref2->{\$i}) {\$exp_hash_ref2->{\$i}=0;} \$final_exp_hash_ref->{\$i}=\$exp_hash_ref1->{\$i}-\$exp_hash_ref2->{\$i}; if((\$exp_hash_ref1->{\$i}!=0)&&(\$exp_hash_ref2->{\$i}!=0)) {\$int_exp_hash->{\$i}="\$i^(\$exp_hash_ref1->{\$i}-\$exp_hash_ref2->{\$i})"; \$intermediate.=\$int_exp_hash->{\$i};} \$final_var.="\$i^\$final_exp_hash_ref->{\$i}" if \$final_exp_hash_ref->{\$i}!=0; \$final_var=~s/\^1\$// if(\$final_var); } if((\$monomials[0]=~m/[a-z]/)&&(\$monomials[1]=~m/[a-z]/)) { \$display="\$final_coefficient\$intermediate"; \$display=~s/(\d+)\/(\d+)/\(\$1\/\$2\)/g; print "

{{{\$display}}} When you divide monomials, simply subtract the exponents.

" if \$print==1; } \$final_var="" unless(\$final_var); \$final_coefficient=1 unless(\$final_coefficient); my \$ans="\$final_coefficient\$final_var"; \$ans=~s/^1([a-z])/\$1/g; \$ans=~s/^(\-?\d+)\/(\d+)([a-z])/(\$1\/\$2)\$3/; \$ans=~s/^\(\-/\-\(/; \$ans=~s/\^\-(\d+)/\^(\-\$1\)/g; if((\$monomials[0]=~m/[a-z]/)&&(\$monomials[1]=~m/[a-z]/)) {print "

{{{\$ans}}} Subtract.

" if \$print==1;} ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return (\$final_coefficient,\$final_var) if ( wantarray ); #-- neither undefined nor list context, return scalar return \$ans; } #my @exp=qw(-2x^2 4x^5yz); #my \$ans1=monomial_division(@exp,1); #print "

(\$exp[0])/(\$exp[1])=\$ans1

"; #input format: 2 strings of arguments and print argument sub monomial_exponentiation { die "Needs 3 arguments " if @_!=3; my \$print=pop; my @monomials=@_; die "Variable in exponent " if \$monomials[1]=~m/[a-z]/; my \$coefficient=monomial_coefficient(\$monomials[0]); my (\$final_exp_hash_ref,\$final_var); \$coefficient=reduce(rat(\$coefficient,\$monomials[1],"^")); my \$exp_hash_ref1=monomial_exponent(\$monomials[0]); # multiply exponents for my \$i ('a'..'z') { unless(exists \$exp_hash_ref1->{\$i}) {\$exp_hash_ref1->{\$i}=0;} \$final_exp_hash_ref->{\$i}=reduce(rat(\$monomials[1],\$exp_hash_ref1->{\$i},"*")); \$final_var.="\$i^\$final_exp_hash_ref->{\$i}" if \$final_exp_hash_ref->{\$i}!=0; \$final_var=~s/\^1\$// if(\$final_var); } my \$ans="\$coefficient\$final_var"; \$ans=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; #print "\$ans\n"; return \$ans; } #my @exp=qw(3x^2yz^3 3); #my \$ans3=monomial_exponentiation(@exp,1); #print "

{{{(\$exp[0])^(\$exp[1])=\$ans3}}}

"; # given a number n, subroutine will generate all perfect squares up to n # eg n=103 ----> perfect squares: 1,4,9,16,25,36,49,64,81,100 sub generate_perfect_squares { my \$n=\$_[0]; my \$sqrt_n=int(sqrt(\$n)); my @ans; for(my \$i=0;\$i<=\$sqrt_n;\$i++) {push(@ans,\$i**2);} shift(@ans) if \$ans[0]==0; return @ans; } # simplify sqrt(72)=sqrt(36)*sqrt(2)=6*sqrt(2) sub simplify_square_root { my \$number=\$_[0]; my \$negative_flag=0; if(\$number=~m/^\-/) {\$negative_flag=1; \$number=~s/\-//;} my \$sq=sqrt(\$number); if(\$sq!~m/\./) {return \$sq if \$negative_flag==0; return "\$sq*i" if \$negative_flag==1;} my @factors=factor_generate(\$number); if(\$negative_flag==0) { if(\$factors[0] eq 'prime') {return ("1","sqrt(\$number)") if ( wantarray ); return "sqrt(\$number)";} } else { if(\$factors[0] eq 'prime') {return ("i","sqrt(\$number)") if ( wantarray ); return "i*sqrt(\$number)";} } my @perfect_squares=generate_perfect_squares(\$number); my @factor; for(my \$i=0;\$i<@perfect_squares;\$i++) { my \$temp=\$number/\$perfect_squares[\$i]; push(@factor,\$perfect_squares[\$i]) if \$temp!~m/\./; } if(@factor==0) { if(\$negative_flag==0) {return ("1","sqrt(\$number)") if ( wantarray ); return "sqrt(\$number)";} else {return ("i","sqrt(\$number)") if ( wantarray ); return "i*sqrt(\$number)";} } my \$factor1=\$number/\$factor[-1]; my \$factor2=\$number/\$factor1; my \$sq_factor1=sqrt(\$factor1); my \$sq_factor2=sqrt(\$factor2); if(\$sq_factor1!~m/\./) {\$factor1=\$sq_factor1;} else {\$factor1="sqrt(\$factor1)";} if(\$sq_factor2!~m/\./) {\$factor2=\$sq_factor2;} else {\$factor2="sqrt(\$factor2)";} if((\$sq_factor1!~m/\./)&&(\$sq_factor2!~m/\./)) {my \$temp=\$factor2*\$factor1; return \$temp if \$negative_flag==0; return "\$temp*i" if \$negative_flag==1; } if(\$negative_flag==1) {\$factor2.="i";} #print " factor2,factor1: \$factor2,\$factor1

"; ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return (\$factor2,\$factor1) if ( wantarray ); #-- neither undefined nor list context, return scalar if(\$negative_flag==0) {return "\$factor2*\$factor1";} else {return "\$factor2*\$factor1";} } sub factor_generate { my \$number=\$_[0]; my (\$count,@factors); \$count=0; for(my \$i=2;\$i{\$i}) {\$exp_hash_ref->{\$i}=0;} if(\$exp_hash_ref->{\$i}<0) { my \$abs=\$exp_hash_ref->{\$i}; \$abs=~s/\-//; \$denom.="\$i^\$abs"; } else {\$num.="\$i^\$exp_hash_ref->{\$i}" if \$exp_hash_ref->{\$i}!=0;} }print "... @coefficient ...\n"; \$num=1 unless \$num; \$denom=1 unless \$denom; return ("\$coefficient[0]?\$num","\$coefficient[1]?\$denom"); } sub decimal_distribution { die " Needs 2 arguments " if @_!=2; my (\$equation,\$print)=@_; my \$sign=\$1 if \$equation=~m/(<=|>=|>|<|=)/; die "Not an equation nor inequality " unless \$sign; #die " Not an equation " if \$equation!~m/=/; return \$equation if \$equation!~m/\./; my (\$left,\$right)=split(/\$sign/,\$equation); my @left_terms=generate_terms(\$left); my @right_terms=generate_terms(\$right); my @left_coefficients=multivariate_coefficient(\$left); my @right_coefficients=multivariate_coefficient(\$right); for(my \$i=0;\$i<@left_terms;\$i++) {\$left_terms[\$i].="x^0" if \$left_terms[\$i]!~m/[a-z]/;} for(my \$i=0;\$i<@right_terms;\$i++) {\$right_terms[\$i].="x^0" if \$right_terms[\$i]!~m/[a-z]/;} my @place_val; for(my \$i=0;\$i<@left_coefficients;\$i++) { my \$place_val=\$1 if \$left_coefficients[\$i]=~m/\.(\d+)/; \$place_val=0 unless \$place_val; \$place_val=length(\$place_val) if \$place_val; push(@place_val,\$place_val) if \$place_val; } for(my \$i=0;\$i<@right_coefficients;\$i++) { my \$place_val=\$1 if \$right_coefficients[\$i]=~m/\.(\d+)/; \$place_val=0 unless \$place_val; \$place_val=length(\$place_val) if \$place_val; push(@place_val,\$place_val) if \$place_val; } #print "

" if \$print==1; @place_val=my_number_sort(@place_val); my \$largest_place_val=\$place_val[-1]; my \$lcd=10**\$largest_place_val; print "

{{{\$lcd(\$left)\$sign\$lcd(\$right)}}} Multiply both sides by \$lcd to clear out the decimals.

" if \$print==1; my (@new_left_terms,@new_right_terms); for(my \$i=0;\$i<@left_coefficients;\$i++) { \$left_coefficients[\$i]*=\$lcd; my \$var=\$2 if \$left_terms[\$i]=~m/(\-?\d+\.\d+|\-?\d+)(.*?)\$/; \$new_left_terms[\$i]="\$left_coefficients[\$i]\$var"; \$new_left_terms[\$i]=~s/[a-z]\^0(\D|\$)/\$1/g; } for(my \$i=0;\$i<@right_coefficients;\$i++) { \$right_coefficients[\$i]*=\$lcd; my \$var=\$2 if \$right_terms[\$i]=~m/(\-?\d+\.\d+|\-?\d+)(.*?)\$/; \$new_right_terms[\$i]="\$right_coefficients[\$i]\$var"; \$new_right_terms[\$i]=~s/[a-z]\^0(\D|\$)/\$1/g; } my \$ans="".join("+",@new_left_terms)."\$sign".join("+",@new_right_terms).""; #print "

{{{\$ans}}} Distribute and multiply.

\$sq_exp=",eval(\$sq_exp),"

\$ans=",eval(\$ans),"

" if \$print==1; return \$ans; } #my \$exp="8/7"; #my \$ans=sqrt_of_fraction(\$exp,1); #print "ANS: {{{sqrt(\$exp)=\$ans}}}\n"; ## if one operand has a decimal portion, use this subroutine sub evaluate_decimal { die "ERROR: You need to enter 3 arguments" if @_!=3; my @a=generate_fraction(\$_[0]); my @b=generate_fraction(\$_[1]); my \$operator=\$_[2]; my (\$num,\$denom); if(\$operator eq '+') { \$num=\$a[0]*\$b[1]+\$b[0]*\$a[1]; \$denom=\$a[1]*\$b[1]; } elsif(\$operator eq '-') { \$num=\$a[0]*\$b[1]-\$b[0]*\$a[1]; \$denom=\$a[1]*\$b[1]; } elsif(\$operator eq '*') { \$num=\$a[0]*\$b[0]; \$denom=\$a[1]*\$b[1]; } elsif(\$operator eq '/') { \$num=\$a[0]*\$b[1]; \$denom=\$a[1]*\$b[0]; } elsif(\$operator eq '^') { my \$exponent=\$b[0]/\$b[1]; \$num=\$a[0]**\$exponent; \$denom=\$a[1]**\$exponent; } else { die "ERROR: \"\$operator\" is not a valid operator"; } my \$ans=\$num/\$denom; return \$ans; } sub rationalize_denominator { die "Needs two arguments " if @_!=2; my (\$exp,\$print)=@_; my (\$num,\$denom)=split(/\//,\$exp); if(\$denom!~m/sqrt/) {warn "Denominator doesn't have square root "; return \$exp;} my @root_denom=\$denom=~m/(sqrt\(.*?\))/g; my (\$temp_num,\$temp_denom); \$temp_num=\$temp_denom=join("",@root_denom); #for(my \$i=0;\$i<@root_denom;\$i++) #{} my \$new_denom=join("",@root_denom); \$new_denom=~s/sqrt\((.*?)\)/\$1/g; my \$ans=clean("(\$num\$temp_num)/(\$new_denom)"); print " {{{\$exp}}} Start with the given expression {{{(\$exp)(\$temp_num/\$temp_denom)}}} Multiply both the numerator and the denominator by {{{\$temp_num}}} {{{",clean("(\$num\$temp_num)/(\$denom\$temp_denom)"),"}}} Combine the fractions {{{",clean("(\$num\$temp_num)/(\$new_denom)"),"}}} Multiply {{{\$denom}}} and {{{\$temp_denom}}} to get {{{\$new_denom}}} " if \$print==1; ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return "\$num\$temp_num",\$new_denom if ( wantarray ); #-- neither undefined nor list context, return scalar return \$ans; } ## main subroutine - Enter strings for operands and operator . ## Ex: rational_arithmetic(2,"2/3","+") ## or rational_arithmetic(\$num1,"@array","/") sub rat { my \$arg_count=@_; if(\$arg_count!=3) {die "ERROR: You need to enter 3 arguments"; return;} my \$operator=pop; # pull last element off of input array @_ if((\$_[0]=~m/\./) or (\$_[1]=~m/\./)) { my \$ans=evaluate_decimal(\$_[0],\$_[1],\$operator); return \$ans; } my @ans; for(my \$i=0;\$i<@_;\$i++) {my \$temp=\$_[\$i]; \$temp=~s/\///; \$temp=~s/\-//g; \$temp=~s/\s//g; if(\$temp=~m/(\D)/) {print "TEMP: \$temp\n"; die "ERROR: nonnumerical character \"\$1\" ";} } my @a=generate_fraction(\$_[0]); my @b=generate_fraction(\$_[1]); if((\$a[1]==0)||(\$b[1]==0)) {print "..\$a[0]..\$a[1]..\$b[0]..\$b[1]..\n"; die "ERROR: Division by zero";} if(\$operator eq '+') {my \$lcm=lcm(\$a[1],\$b[1]); \$a[0]=(\$lcm/\$a[1])*\$a[0]; \$b[0]=(\$lcm/\$b[1])*\$b[0]; \$a[1]=\$b[1]=\$lcm; @ans=(\$a[0]+\$b[0],\$a[1]); } elsif(\$operator eq '-') {my \$lcm=lcm(\$a[1],\$b[1]); \$a[0]=(\$lcm/\$a[1])*\$a[0]; \$b[0]=(\$lcm/\$b[1])*\$b[0]; \$a[1]=\$b[1]=\$lcm; @ans=(\$a[0]-\$b[0],\$a[1]); } elsif(\$operator eq '*') {@ans=(\$a[0]*\$b[0],\$a[1]*\$b[1]);} elsif(\$operator eq '/') {@ans=(\$a[0]*\$b[1],\$a[1]*\$b[0]);} elsif(\$operator eq '^') {if(\$b[1]==1) {@ans=(\$a[0]**\$b[0],\$a[1]**\$b[0]);} elsif((\$b[0]==1)&&(\$b[1]==2)) {my \$temp=sqrt_of_fraction(join("/",@a)); return \$temp} else {die "ERROR: exponent ".join("/",@b)." is a fraction b_1=\$b[1]"; return;} } else {die "ERROR: \"\$operator\" is not a valid operator";} ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return @ans if ( wantarray ); #-- neither undefined nor list context, return scalar return join("/",@ans); } ## sort x^2ry to get rx^2y sub my_alphabetical_sort { my \$temp_a=\$1 if \$a=~m/([a-z])/; my \$temp_b=\$1 if \$b=~m/([a-z])/; return \$temp_a cmp \$temp_b; } sub combine_like_terms { my (\$exp,\$print)=@_; \$exp=~s/(\+|\-|^)(\d+\/\d+|\d+)(?=\+|\-|\$)/\$1\$2 x\^0\$3/g; \$exp=~s/(\+|\-|^)0(\+|\-|\$)/\$1\$2/g; # remove any 0 terms ie 5+0-2+0=5-2 \$exp=~s/\s//g; \$exp=~s/\+\-/\-/g; \$exp=~s/\-\-/\+/g; \$exp=~s/^\++//; my @terms=generate_terms(\$exp); my (%terms_hash,%intermediate_hash); # sort the terms of each monomial for(my \$i=0;\$i<@terms ;\$i++) {\$terms[\$i]=monomial_sort(\$terms[\$i]);} print "

" if \$print==1; for(my \$i=0;\$i<@terms;\$i++) {my \$coefficient=\$1 if \$terms[\$i]=~m/^(.*?)[a-z]/; \$terms[\$i]=~s/^\$coefficient//; \$terms_hash{\$terms[\$i]}=reduce(rat(\$terms_hash{\$terms[\$i]},\$coefficient,"+")) if(exists \$terms_hash{\$terms[\$i]}); \$terms_hash{\$terms[\$i]}=\$coefficient unless(exists \$terms_hash{\$terms[\$i]}); \$intermediate_hash{\$terms[\$i]}.="\$coefficient\$terms[\$i]+"; } my @intermediate=values(%intermediate_hash); @intermediate=map{s/\+\-/\-/g;\$_} @intermediate; @intermediate=map{s/\+\$//;\$_} @intermediate; print "

{{{(".join(")+(",@intermediate).")}}} Group like terms

" if \$print==1; my @combined_terms_keys=keys %terms_hash; ## sort optional #@combined_terms_keys=sort{my_alphabetical_sort} @combined_terms_keys; my \$ans; for(my \$i=0;\$i<@combined_terms_keys;\$i++) {\$ans.="\$terms_hash{\$combined_terms_keys[\$i]}\$combined_terms_keys[\$i]+";} \$ans=~s/\+\$//; \$ans=~s/\+\-/\-/g; \$ans=~s/\-\-/\+/g; \$ans=~s/(\D|^)1([a-z])/\$1\$2/g; \$ans=~s/(\+|\-|^)[a-z]\^0(\D|\$)/\$1 1\$2/g; # replace +x^0 with +1 or -x^0 with -1 \$ans=~s/(\d+)[a-z]\^0(\D|\$)/\$1\$2/g; # replace +3x^0 with +3 or -5x^0 with -5 \$ans=~s/\s//g; \$ans=~s/^\++//; print "

{{{\$ans}}} Combine like terms

" if \$print==1; print "

So {{{\$exp=\$ans}}}

" if \$print==1; \$ans=0 if length(\$ans)==0; \$ans=0 unless \$ans; return \$ans; } sub monomial_sort { my \$exp=\$_[0]; \$exp=~s/([a-z])([a-z])/\$1\*\$2/g; \$exp=~s/(\d+)([a-z])/\$1\*\$2/g; my @terms=split(/\*/,\$exp); @terms=my_char_sort(@terms); ## Last few lines allow for overloading return values #-- undefined context -- return nothing return if ( ! defined wantarray ); #-- list/array context -- return array return @terms if ( wantarray ); #-- neither undefined nor list context, return scalar return join("",@terms); } sub check_for_illegal_characters { die "Needs 3 arguments " if @_!=3; my (\$exp,\$safe_chars,\$flag)=@_; ##note: flag =1 words allowed flag=0 only numeric characters allowed \$exp=~s/\s//g; my @safe_chars=split(/,/,\$safe_chars); @safe_chars=map(quotemeta(\$_),@safe_chars); my (@illegal_chars,\$illegal_chars_string); for(my \$i=0;\$i<@safe_chars;\$i++) {\$exp=~s/\$safe_chars[\$i]//g;} my \$regexp="\\W+" if \$flag==1; # pick out any non-word chars \$regexp="\\D+" if \$flag==0; # pick out any non-numeric chars if(1) { @illegal_chars=\$exp=~m/(\$regexp)/g; \$illegal_chars_string=join(" ",@illegal_chars); if(\$exp=~m/\$regexp/) { #print "\nILLEGAL: \$illegal_chars_string\n"; return (1,\$illegal_chars_string) if ( wantarray ); return 1; } ## found non-word char, so must return error if(\$exp!~m/\$regexp/) { return (0,"null") if ( wantarray ); return 0; } ## did not find non-word char } # if(\$flag==0) # { # @illegal_chars=\$exp=~m/(\D+)/g; # \$illegal_chars_string=join(" ",@illegal_chars); # if(\$exp=~m/\D/) # { # return (1,\$illegal_chars_string) if ( wantarray ); # return 1; # } ## found non-word char, so must return error # if(\$exp!~m/\D/) # { # return (0,"null") if ( wantarray ); # return 0; # } ## did not find non-word char # } } # format 2 input strings and an operator (only * and / for now) sub monomial_arithmetic { die "Needs 4 arguments " if @_!=4; my \$print=pop; my \$op=pop; my @arguments=@_; my \$ans; for(my \$i=0;\$i<@arguments;\$i++) {\$arguments[\$i]=rewrite_fraction(\$arguments[\$i]);} @arguments=map{s/\(|\)//g;\$_} @arguments; print "

" if \$print==1; if(\$op eq '*') {\$ans=monomial_multiplication(@arguments,\$print);} elsif(\$op eq '/') {\$ans=monomial_division(@arguments,\$print);} elsif(\$op eq '^') {\$ans=monomial_exponentiation(@arguments,\$print);} else {die "Invalid operator \"\$op\" ";} #print "{{{(".join(")\$op(",@arguments).")=\$ans}}}\n"; return \$ans; } sub distribute_generate_terms { my \$exp=\$_[0]; \$exp=~s/\-/\+\-/g; \$exp=~s/(^|\()\+/\$1/g; \$exp=~s/\++/\+/g; my @terms=split(/\+/,\$exp); #print "\n distribute_generate_terms:\$exp @terms SIZE: ".@terms." \n"; return @terms; } # convert a(b+c) to ab+ac sub distribute_single { die "Needs 2 arguments " if @_!=2; my (\$outer,\$inner)=@_; (\$outer,\$inner)=map{s/\s//g;\$_} (\$outer,\$inner); (\$outer,\$inner)=map{s/\(|\)//g;\$_} (\$outer,\$inner); my @inner_terms=distribute_generate_terms(\$inner); my @inner_coefficients=multivariate_coefficient(\$inner); #my @new_inner_coefficients=@inner_coefficients; #@new_inner_coefficients=map(\$_*=\$outer,@new_inner_coefficients); my @new_inner_terms; for(my \$i=0;\$i<@inner_terms;\$i++) { (\$outer,\$inner_terms[\$i])=map{s/\[/\(/g;\$_} (\$outer,\$inner_terms[\$i]); (\$outer,\$inner_terms[\$i])=map{s/\]/\)/g;\$_} (\$outer,\$inner_terms[\$i]); #print " SIZE: ".@inner_terms." ... \$outer,\$inner_terms[\$i] = "; \$new_inner_terms[\$i]=monomial_arithmetic(\$outer,\$inner_terms[\$i],"*",0); #print " \$new_inner_terms[\$i]\n"; \$new_inner_terms[\$i]=~s/x\^0\$//; \$new_inner_terms[\$i]=~s/\*//; \$new_inner_terms[\$i]="+\$new_inner_terms[\$i]"; } my \$ans=join("+",@new_inner_terms); \$ans=~s/\++/\+/g; \$ans=~s/\+\-/\-/g; \$ans=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$ans=~s/\++/\+/g; \$ans=~s/(^|\()\+/\$1/g; #print "\n\$outer(\$inner)=\$ans\n"; return \$ans; } sub distribute { die "Needs 2 arguments" if @_!=2; my (\$exp,\$print)=@_; return \$exp if \$exp!~m/\(/; my \$display=\$exp; \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; \$display=~s/\[/\(/g; \$display=~s/\]/\)/g; \$display=~s/\+\-/\-/g; print "

" if \$print==1; \$exp=~s/\-/\+\-/g; \$exp=~s/(^|\()\+/\$1/g; ## replace (1/2) with [1/2] \$exp=~s/(.*?)\((\-?\d+\/\d+)\)/\$1\[\$2\]/g; my @inners=\$exp=~m/\((.*?)\)/g; #print "SUBROUTINE: distribute: \$exp

"; my \$ans; if(@inners==0) { my (\$term1,\$term2)=\$exp=~m/^(.*?)\[(.*?)\]/g; \$ans=monomial_arithmetic(\$term1,\$term2,"*",0); #print "DONE!"; return \$ans; } my %inner_hash; for(my \$i=0;\$i<@inners;\$i++) { my \$temp_re=quotemeta(\$inners[\$i]); \$inner_hash{\$i}=\$inners[\$i]; \$exp=~s/\(\$temp_re\)/\(??\$i??\)/; #\$inners[\$i]=~s/\+/??0??/g; #print "inner_hash{\$i}=\$inner_hash{\$i} "; } my \$hash_max_index=@inners; #print "

{{{\$exp}}}

"; my @terms=split(/\+/,\$exp); #\$exp=\$display; ## optional #print "

EXP: \$exp TERMS: @terms

"; my @new_terms; #=\$exp; for(my \$i=0;\$i<@terms;\$i++) { my (\$outer,\$inner,\$temp_ans); if(\$terms[\$i]=~m/\(/) { (\$outer,\$inner)=\$terms[\$i]=~m/^(.*?)\((.*?)\)\$/; my \$index=\$1 if \$inner=~m/\?\?(\d+)\?\?/; \$inner=\$inner_hash{\$index}; \$temp_ans=distribute_single(\$outer,\$inner); #print "

Distribute {{{\$outer}}} to the term {{{\$inner}}} to get {{{\$temp_ans}}}\n"; \$new_terms[\$i]=\$temp_ans; } elsif(\$terms[\$i]=~m/\[/) { (\$outer,\$inner)=\$terms[\$i]=~m/^(.*?)\[(.*?)\]\$/; \$temp_ans=distribute_single(\$outer,\$inner); \$new_terms[\$i]=\$temp_ans; } else {\$new_terms[\$i]=\$terms[\$i];} #my \$terms_re=quotemeta(\$terms[\$i]); #print "

Outer: \$outer, Inner: \$inner

"; #my \$temp_ans=distribute_single(\$outer,\$inner); #\$ans=~s/\$terms_re/\$temp_ans/; #print "

Distribute {{{\$outer}}} to the term {{{\$inner}}} to get {{{\$temp_ans}}}. \$left_overs \$terms_re

" if \$print==1; } \$ans=join("+",@new_terms); \$ans=~s/\+\-/\-/g; print "

{{{\$ans}}} Distribute.

" if \$print==1; return \$ans; #print "

ANS: @terms ---> @new_terms

"; #exit; } sub distribute_lcd { my (\$exp,\$print)=@_; return \$exp if \$exp!~m/\//; my \$sign=\$1 if \$exp=~m/(<=|>=|>|<|=)/; die "Not an equation nor inequality " unless \$sign; my (\$left,\$right)=split(/\$sign/,\$exp); my @denominators=\$exp=~m/\/\(?(\-?\d+)\)?/g; my \$lcm=multilcm(@denominators); my \$new_left=distribute("\$lcm(\$left)",0); my \$new_right=distribute("\$lcm(\$right)",0); return ("\$new_left\$sign\$new_right",\$lcm); } sub clear_fractions_and_decimals_clean { my \$exp=\$_[0]; \$exp=~s/\+\-/\-/g; \$exp=~s/\-\-/\+/g; \$exp=~s/(^|=)\+//; \$exp=~s/(\+|\-|^)1([a-z])/\$1\$2/g; #\$exp=~s/(\d+\.\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$exp=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$exp=~s/\+(\$|\))/\$1/g; \$exp=~s/(^|=)\+/\$1/g; return \$exp; } sub clear_fractions_and_decimals { die "Needs two arguments " if @_!=2; my (\$equation,\$print)=@_; \$equation=~s/\(|\)//g; \$equation=~s/\s//g; my \$sign=\$1 if \$equation=~m/(<=|>=|>|<|=)/; die "Not an equation nor inequality " unless \$sign; #die " Not an equation " if \$equation!~m/=/; my \$fraction_flag=0; my \$decimal_flag=0; \$fraction_flag=1 if \$equation=~m/\//; \$decimal_flag=1 if \$equation=~m/\./; return \$equation if \$fraction_flag==0 && \$decimal_flag==0; my \$display=clear_fractions_and_decimals_clean("\$equation"); #print "{{{\$display}}} Start with the given equation.

" if \$print==1; my (\$left,\$right)=split(/\$sign/,\$equation); my (\$fraction_less_equation,\$fraction_lcd)=distribute_lcd(\$equation,0); ## first remove any fractions note: all denominators are WHOLE numbers if(\$fraction_flag==1) { if(\$equation ne \$fraction_less_equation) { \$display=clear_fractions_and_decimals_clean("\$fraction_lcd(\$left)\$sign\$fraction_lcd(\$right)"); my \$lcd_note="note: If you need help with finding the LCD, check out this solver. "; \$display=~s/\/(\-?\d+)/\/cross\(\$1\)/g; \$display=~s/\/\((\-?\d+)\)/\/\(cross\(\$1\)\)/g; print "

{{{\$display}}} Multiply both sides by the LCD {{{\$fraction_lcd}}} to clear any fractions.

" if \$print==1; print "

{{{\$fraction_less_equation}}} Distribute and multiply.

" if \$print==1; } } return \$fraction_less_equation if \$decimal_flag==0; ## now remove any decimals my (\$ans,\$decimal_lcd); if(\$decimal_flag==1) { if((\$equation ne \$fraction_less_equation)&&(\$fraction_flag==1)) { (\$ans,\$decimal_lcd)=decimal_distribution(\$fraction_less_equation,1); \$ans=~s/\+\-/\-/g; print "

{{{\$ans}}} Distribute and multiply.

" if \$print==1; } else { (\$ans,\$decimal_lcd)=decimal_distribution(\$fraction_less_equation,1); \$ans=~s/\+\-/\-/g; print "

{{{\$ans}}} Distribute and multiply.

" if \$print==1; } } return \$ans; } #use rational_arithmetic qw(rat reduce invert_fraction); #use clear_fractions_and_decimals qw(clear_fractions_and_decimals); #use distribute qw(distribute); #use check_for_illegal_characters qw(check_for_illegal_characters); ## Check to see if one expression is a rearrangement of the other eg x+y is same as y+x ## returns TRUE if it is, FALSE otherwise sub check_for_rearrangement { die "Needs two arguments " if @_!=2; my (\$exp1,\$exp2)=@_; my @terms1=generate_terms(\$exp1); my @terms2=generate_terms(\$exp2); #my \$size_terms1=@terms1; #my \$size_terms2=@terms2; for(my \$i=0;\$i<@terms1;\$i++) { for(my \$j=0;\$j<@terms2;\$j++) { if(\$terms1[\$i] eq \$terms2[\$j]) { \$terms1[\$i]="??"; \$terms2[\$j]="??"; } } } my \$new_exp1=join("",@terms1); my \$new_exp2=join("",@terms2); \$new_exp1=~s/\?+//g; \$new_exp2=~s/\?+//g; ## return FALSE if one expression is NOT a rearrangement of the other return 0 if((length(\$new_exp1)>0)||(length(\$new_exp2)>0)); ## return TRUE if one expression is a rearrangement of the other return 1 if((length(\$new_exp1)==0)&&(length(\$new_exp2)==0)); } sub round { die "Only two arguments are accepted here: num to be rounded and number of places to round to" if @_!=2; my (\$num,\$precision)=@_; return \$num if \$num!~m/\./; die "precision must be positive" if \$precision<0; my (\$whole, \$decimal_portion)=split(/\./,\$num); my @digits_after_decimal=split(//,\$decimal_portion); if(\$precision==0) { return ++\$whole if \$digits_after_decimal[0]>=5; return \$whole if \$digits_after_decimal[0]<5; } else { if(\$digits_after_decimal[\$precision]>=5) { \$digits_after_decimal[\$precision-1]++; } my \$new_decimal_portion=""; for(my \$i=0;\$i<\$precision;\$i++) { \$new_decimal_portion.="\$digits_after_decimal[\$i]"; } \$new_decimal_portion=~s/0+\$//; ## remove any trailing zeros return "\$whole.\$new_decimal_portion" if \$new_decimal_portion; return "\$whole" unless \$new_decimal_portion; } } sub linear_equation_solver_clean { my \$exp=\$_[0]; \$exp=~s/\+\-/\-/g; \$exp=~s/\-\-/\+/g; \$exp=~s/(^|=)\+//; \$exp=~s/(^|=|\+|\-)1([a-z])/\$1\$2/g; ## optional return \$exp; } #my \$equation="x+y+x+z=5-x"; #my \$equation="1/2x+3+x+6=5-x"; sub linear_equation_solver { die "Needs 4 arguments: equation, var,show,print " if @_!=4; my (\$equation,\$var,\$show,\$print)=@_; \$equation=~tr/[A-Z]/[a-z]/; \$equation=~s/\s//g; \$equation=~s/(<=|>=|>|<)/=/; my (\$check_left,\$check_right)=split(/=/,\$equation); # return the right side if equation is already solved for... #return \$check_right if \$check_left eq \$var; my @reserved_math_keywords=qw(sin cos tan csc sec cot log ln sqrt abs root); for(my \$i=0;\$i<@reserved_math_keywords;\$i++) {die "Cannot compute \"\$reserved_math_keywords[\$i]\" " if \$equation=~m/\$reserved_math_keywords[\$i]/;} #my \$var="x"; ## this is the variable you want to solve for die "Equation is NOT linear " if \$equation=~m/[a-z]{2,}/; die "Equation is NOT linear since it contains a division by a variable " if \$equation=~m/\/[a-z]/; die "The variable \"\$var\" is NOT in equation \$equation " if \$equation!~m/\$var/; die "Variable to solve for is NOT defined " unless \$var; die " Equation cannot contain exponents " if \$equation=~m/\^/; die " Equation cannot contain variable(... " if \$equation=~m/[a-z]\(/; die " Equation cannot contain variable^#(... " if \$equation=~m/[a-z]\^\d+\(/; my \$original_equation=\$equation; ## check for illegal characters my (\$illegal_char_bool)=check_for_illegal_characters(\$equation,"+,-,*,/,.,(,),=",1); die "Equation contains illegal characters " if \$illegal_char_bool==1; # if variable to solve for is NOT specified, solve for FIRST variable found # unless(\$var) # {\$var=\$1 if \$equation=~m/([a-z])/;} #my \$print=1; ## this allows you to turn on/off print statements #print "TEST"; \$equation.="=0" if \$equation!~m/=/; # set equation equal to zero if equal sign is not given my \$display=linear_equation_solver_clean(\$equation); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

" if \$print==1 && \$show==1; my \$old=\$equation; my (\$temp_left,\$temp_right)=split(/=/,\$equation); my @left_inners=\$temp_left=~m/\((.*?)\)/g; my @right_inners=\$temp_right=~m/\((.*?)\)/g; \$temp_left=~s/\)/\+0\)/g; \$temp_right=~s/\)/\+0\)/g; (\$temp_left,\$temp_right)=(distribute(\$temp_left,0),distribute(\$temp_right,0)); (\$temp_left,\$temp_right)=map{s/\+0//g;\$_}(\$temp_left,\$temp_right); (\$temp_left,\$temp_right)=map{s/(\D)\./\$1 0\./g;\$_}(\$temp_left,\$temp_right); (\$temp_left,\$temp_right)=map{s/\s//g;\$_}(\$temp_left,\$temp_right); \$equation="\$temp_left=\$temp_right"; if(\$equation ne \$old) { my \$left_plus_count=0; my \$right_plus_count=0; for(my \$k=0;\$k<@left_inners;\$k++) { my \$temp1=\$left_inners[\$k]; \$temp1=~s/\-/\+\-/g; \$temp1=~s/^\+//; if(\$temp1=~m/\+/) {\$left_plus_count++;} } for(my \$k=0;\$k<@right_inners;\$k++) { my \$temp1=\$right_inners[\$k]; \$temp1=~s/\-/\+\-/g; \$temp1=~s/^\+//; if(\$temp1=~m/\+/) {\$right_plus_count++;} } if((\$left_plus_count>0)||(\$right_plus_count>0)) { print "

{{{",linear_equation_solver_clean(\$equation),"}}} Distribute.

" if \$print==1; } else { print "

{{{",linear_equation_solver_clean(\$equation),"}}} Multiply.

" if \$print==1; } } ## clear out fractions and decimals from equation \$equation=clear_fractions_and_decimals(\$equation,\$print); my (\$left,\$right)=split(/=/,\$equation); #print "AFTER clear_fractions_and_decimals:\n"; my (\$old_left,\$old_right)=(\$left,\$right); \$left=combine_like_terms(\$left); \$right=combine_like_terms(\$right); ## recheck to see if there are any exponents die " Equation cannot contain exponents after distribution/clearing " if \$equation=~m/\^/; die "Equation is NOT linear " if \$equation=~m/[a-z]{2,}/; die "Equation is NOT linear since it contains a division by a variable " if \$equation=~m/\/[a-z]/; die "The variable \"\$var\" is NOT in equation \$equation " if \$equation!~m/\$var/; die "Variable to solve for is NOT defined " unless \$var; die " Equation cannot contain exponents " if \$equation=~m/\^/; my \$left_bool=check_for_rearrangement(\$old_left,\$left); my \$right_bool=check_for_rearrangement(\$old_right,\$right); \$left=\$old_left if \$left_bool==1; \$right=\$old_right if \$right_bool==1; if(\$old_left ne \$left) { \$left=0 unless \$left; \$display=linear_equation_solver_clean("\$left=\$old_right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} Combine like terms on the left side.

" if \$print==1; } if(\$old_right ne \$right) { \$right=0 unless \$right; \$display=linear_equation_solver_clean("\$left=\$right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} Combine like terms on the right side.

" if \$print==1; } my @left_terms=generate_terms(\$left); my @right_terms=generate_terms(\$right); ## replace 1x with x @left_terms=map{s/^1([a-z])/\$1/;\$_} @left_terms; @right_terms=map{s/^1([a-z])/\$1/;\$_} @right_terms; ## replace -1x with -x @left_terms=map{s/^\-1([a-z])/\-\$1/;\$_} @left_terms; @right_terms=map{s/^\-1([a-z])/\-\$1/;\$_} @right_terms; my \$left_size=@left_terms; my \$right_size=@right_terms; my \$count=0; # cycle through left terms and keep terms with variable you want to solve for # place everything else on the right side for(my \$i=0;\$i<\$left_size;\$i++) { if(exists \$left_terms[\$i]) { if(\$left_terms[\$i]!~m/\$var/) { my \$temp=splice(@left_terms,\$i,1); my \$hold=\$temp; \$i--; \$temp=linear_equation_solver_clean("-\$temp"); push(@right_terms,\$temp); my \$temp_left=linear_equation_solver_clean(join("+",@left_terms)); my \$temp_right=linear_equation_solver_clean(join("+",@right_terms)); my \$abs=\$temp; \$abs=~s/\-//; \$temp_left=0 unless \$temp_left; \$temp_right=0 unless \$temp_right; \$display=linear_equation_solver_clean("\$temp_left=\$temp_right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} " if \$print==1; print "", (\$hold=~m/\-/) ? "Add {{{\$abs}}} to ":"Subtract {{{\$abs}}} from " if \$print==1; print "both sides.

" if \$print==1; } } } # cycle through right terms and place terms with variable you want to solve for on the left side # keep everything else on the right side for(my \$i=0;\$i<\$right_size;\$i++) { if(exists \$right_terms[\$i]) { if(\$right_terms[\$i]=~m/\$var/) { my \$temp=splice(@right_terms,\$i,1); my \$hold=\$temp; \$i--; \$temp=linear_equation_solver_clean("-\$temp"); push(@left_terms,\$temp); my \$temp_left=linear_equation_solver_clean(join("+",@left_terms)); my \$temp_right=linear_equation_solver_clean(join("+",@right_terms)); my \$abs=\$temp; \$abs=~s/\-//; \$temp_left=0 unless \$temp_left; \$temp_right=0 unless \$temp_right; \$display=linear_equation_solver_clean("\$temp_left=\$temp_right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} " if \$print==1; print "", (\$hold=~m/\-/) ? "Add {{{\$abs}}} to ":"Subtract {{{\$abs}}} from " if \$print==1; print "both sides.

" if \$print==1; } } } ## now combine like terms (\$left,\$right)=(linear_equation_solver_clean(join("+",@left_terms)),linear_equation_solver_clean(join("+",@right_terms))); \$left=0 unless(defined \$left); \$left=0 if(length(\$left)==0); \$right=0 unless(defined \$right); \$right=0 if(length(\$right)==0); (\$old_left,\$old_right)=(\$left,\$right); \$left=combine_like_terms(\$left); \$right=combine_like_terms(\$right); \$left_bool=check_for_rearrangement(\$old_left,\$left); \$right_bool=check_for_rearrangement(\$old_right,\$right); \$left=\$old_left if \$left_bool==1; \$right=\$old_right if \$right_bool==1; if(\$old_left ne \$left) { \$left=0 unless \$left; \$display=linear_equation_solver_clean("\$left=\$old_right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} Combine like terms on the left side.

" if \$print==1; } if(\$old_right ne \$right) { \$right=0 unless \$right; \$display=linear_equation_solver_clean("\$left=\$right"); \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$display=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; print "

{{{\$display}}} Combine like terms on the right side.

" if \$print==1; } # if(\$right=~m/^0\D/) # { # \$right=~s/^0\+//; # \$right=~s/^0\-/\-/; # \$display=linear_equation_solver_clean("\$left=\$right"); # \$display=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; # print "

{{{\$display}}} Combine like terms.

" if \$print==1; # } ## now divide both sides by whole number OR multiply both sides by reciprocal of fraction my \$ans; my @final_coefficient=multivariate_coefficient(\$left); my \$final_coefficient=\$final_coefficient[0]; if(\$final_coefficient eq '0') {## if 0=0 if(\$right eq '0') { print "

{{{0=0}}} Simplify.

" if \$print==1; print "

Since this equation is always true for any \$var value, this means \$var can equal any number. So there are an infinite number of solutions.

" if \$print==1; return "INF"; } elsif(\$right ne '0') { print "

{{{0=\$right}}} Simplify.

" if \$print==1; print "

Since this equation is never true for any \$var value, this means that there are no solutions.

" if \$print==1; return "UND"; } } ## Case # 1: divide both sides by whole number if(\$final_coefficient!~m/\//) { if(\$final_coefficient!=1) { print "

{{{\$var=(\$right)/(\$final_coefficient)}}} Divide both sides by {{{\$final_coefficient}}} to isolate {{{\$var}}}.

" if \$print==1; if(\$right!~m/[a-z]/) { \$ans=reduce(rat(\$right,\$final_coefficient,"/")); if("\$right/\$final_coefficient" ne \$ans) {print "

{{{\$var=\$ans}}} Reduce.

" if \$print==1;} } else {\$ans="(\$right)/(\$final_coefficient)";} } else {\$ans=\$right;} } ## Case # 2: multiply both sides by the reciprocal of the fraction if(\$final_coefficient=~m/\//) { my \$inverted_coefficient=reduce(invert_fraction(\$final_coefficient)); \$display=linear_equation_solver_clean("(\$inverted_coefficient)(\$right)"); \$display=~s/\((\-?\d+)\)\(/\$1\(/g; print "

{{{\$var=\$display}}} Multiply both sides by the {{{\$inverted_coefficient}}} to isolate {{{\$var}}}.

" if \$print==1; if(\$right!~m/[a-z]/) { \$ans=reduce(rat(\$right,\$final_coefficient,"/")); if("\$right/\$final_coefficient" ne \$ans) { print "

{{{\$var=\$ans}}} Multiply" if \$print==1; if((\$inverted_coefficient=~m/\//)||(\$right=~m/\//)) {print " and reduce.

" if \$print==1;} else {print ".

" if \$print==1;} } } else {\$ans="(\$right)/(\$final_coefficient)";} } print "

----------------------------------------------------------------------

" if \$print==1 && \$show==1; print "\nAnswer:\n" if \$print==1 && \$show==1; print "

So the solution is {{{\$var=\$ans}}} " if \$print==1 && \$show==1; if((\$right!~m/[a-z]/)&&(\$ans=~m/\//)) { #my \$approx_ans=eval("\$ans"); #\$approx_ans = nearest(0.001, \$approx_ans); #print "which approximates to {{{\$var=\$approx_ans}}}.

" if \$print==1 && \$show==1; } else {print "

" if \$print==1 && \$show==1;} my \$check1=\$original_equation; \$check1=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$check1=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; \$check1=~s/=(.*?)\$/\-\(\$1\)/; \$check1=~s/\$var/\(\$ans\)/g; my \$check2=\$equation; \$check2=~s/(\d+)\/(\d+)([a-z])/\(\$1\/\$2\)\$3/g; \$check2=~s/(\d+)\/(\d+)\(/\(\$1\/\$2\)\(/g; \$check2=~s/=(.*?)\$/\-\(\$1\)/; \$check2=~s/\$var/\(\$ans\)/g; #print "

CHECK1: \$check1 " if \$print==1 && \$show==1; #print "

CHECK2: \$check2" if \$print==1 && \$show==1; return \$ans; } # # #print "

END

"; #print "

----------------------------------------------------------------------