use strict; use warnings; use feature "say"; use constant DEBUG => 1; my $epsilon = 1e-12; # precision my ($result, $step) = (0, 10); # arbitrary start values my $equation = "(2*(4*x-8)+3*x)-(10*x+1-9)"; # " = 0" omitted $equation =~ s/x/\$x/g; my $eval = create_eval($equation); # currying the equation for simplicity my $debug = 1; while (1) { my $val = $eval->($result); last if abs $val < $epsilon; my $new_result = $result + $step; my $temp = $eval->($new_result); say "x = $result ; val = $val ; temp = $temp; step = $step" if DEBUG; $result = $new_result and last if abs $temp < $epsilon; if ($temp == $val) { say "No solution for this equation"; undef $result; last; } if (($val > 0 and $temp < 0) or ($val < 0 and $temp > 0)) { while (1) { $step = 0; my $avg = ($result + $new_result) /2; my $avg_val = $eval->($avg); # say "x = $result; val = $val ; temp = $temp; step = $step; avg = $avg" if DEBUG; printf "%s%.15f%s%.15f%s%.15f%s%.15f\n", "x = ", $result, " val = ", $val, " temp = ", $temp, " avg = ", $avg; $new_result = $avg and last if abs $avg_val < $epsilon; if ($avg_val > 0) { $result = $avg and $val= $avg_val if $val > 0; $new_result = $avg and $temp = $avg_val if $temp > 0; } else { $result = $avg and $val = $avg_val if $val < 0; $new_result = $avg and $temp = $avg_val if $temp < 0; } } } $step = -$step and next if $temp < $val and $val < 0; $step /= 2 and next if abs $temp > abs $val; # we are further from 0, reduce step by half $result =$new_result; # $temp is closer to 0, let's continue with $new_resultp } printf "%s%.10f\n", "Result is: ", $result;# if defined $result; sub create_eval { my $formula = shift; return sub { my $x = shift; return eval($formula);} }