use strict;
use warnings;

use constant EPS => 1E-10;

sub f
  {
  my $x = shift;
  return (exp(-$x) - 2.0*$x);
  }

my $y = nullstelle(0.3, 0.4, \&f);
printf("Nullstelle: %.4f Funktionswert: %.4f\n", $y, f($y));

# Ergebnis: Nullstelle: 0.3517 Funktionswert: -0.0000


sub nullstelle #($a, $b, \&f(x))
  {
  my ($a, $b, $f) = @_;
  my ($x);
  # Hilfsvariable verhindern mehrfaches Auswerten
  # der Funktion --> schneller
  my $fa = &{$f}($a);         # Anfangswerte berechnen
  my $fb = &{$f}($b);
  my $fx = $fb;
  while (abs($fx) > EPS)
    {
    # Regula falsi anwenden
    $x = $a - $fa*($b - $a)/($fb - $fa);
    # Funktionswert berechnen
    $fx = &{$f}($x);
    if (($fa * $fx) > 0)
      { $a = $x; $fa = $fx; } # Nullstelle im rechten Intervall
    else
      { $b = $x; $fb = $fx; } # Nullstelle im linken Intervall
    }
  return($x);
  }
