Code kata: numeric integration

  • Posted on
  • by

В продолжение http://friendfeed.com/kkapp/b5d3658c.

Численные методы вычисления аналитически сложных функций всегда казались очень крутым хаком реальности, жалко, что в работе применить не удалось.

Простейшая численная интеграция линейными функциями. Потратил условный час работы в течение двух дней. Тесты вычислял руками и ВольфрамАльфой.

#! /usr/bin/perl
use strict;
use warnings;

use List::Util qw/sum/;

use Test::Most;
use Test::Number::Delta within => 0.001;
use Data::Dump;

my $EPS = 0.000001;

sub integrate {
	my ($f, $x1, $x2) = @_;

	my $d = 1;
	my ($cur, $prev) = 0;

	do {
		my $dx = ($x2 - $x1) / $d;

		$prev = $cur;
		$cur = sum
			map { $dx * (
				$f->($x1 + $dx * $_)
				+ ($f->($x1 + $dx * ($_ + 1)) - $f->($x1 + $dx * $_)) / 2)
			    } 0 .. ($d - 1);

		$d *= 2;
	}
	while (abs($cur - $prev) > $EPS);

	return $cur;
}

delta_ok(integrate(sub { $_[0] * 10 }, 2, 5), 105);
delta_ok(integrate(sub { 100 - $_[0] * 10 }, 2, 5), 195);
delta_ok(integrate(sub { 3 }, 1, 10), 27);
delta_ok(integrate(sub { -2 * $_[0] }, -3, 4), -7);

delta_ok(integrate(sub { $_[0] ** 2 }, 0, 5), 125/3);
delta_ok(integrate(sub { sin($_[0]) }, 0, 3.1415), 2);
delta_ok(integrate(sub { sin($_[0]) }, 0, 3 * 3.1415), 2);
delta_ok(integrate(sub { -($_[0] ** 4) }, -5, -2), -3093/5);
done_testing;