use strict;
use warnings;

use constant EPS => 1E-10;

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

my $y = nullstelle(0.3, 100, \&f);
printf("Nullstelle f: %.4f Funktionswert: %.4f\n", $y, f($y));
# Ergebnis: Nullstelle f: 0.3517 Funktionswert: 0.0000

my $y = nullstelle(3, 100, \&g);
printf("Nullstelle g: %.4f Funktionswert: %.4f\n", $y, g($y));
# Ergebnis: Nullstelle g: 2.6452 Funktionswert: -0.0000


sub nullstelle #($a, $imax, \&f(x))
  {
  use constant dH => 1e-6;
  my ($a, $imax, $f) = @_;
  my ($x);
  my $it = 0; 

  # Anfangswerte berechnen
  my $fa = &{$f}($a);
  # numerische Ableitung f'($a)
  my $fs = (&{$f}($a+dH) - $fa)/dH;
  while ($it <= $imax)
    {
    # verschwindende Ableitung abfangen 
    return $a if (abs($fs) < EPS);
    # Genauigkeit erreicht?
    return $a if (abs($fa) < EPS);
    # Berechnung des neuen Funktionswerts/Ableitung
    $fa = &{$f}($a);
    $fs = (&{$f}($a + dH) - $fa)/dH; 
    $a = $a - $fa/$fs;
    $it++;
    }
  warn "Maximalzahl der Iterationen $imax erreicht\n";
  return $a;   # $imax erreicht
  }
