使用计算 f 在 [0,1] 上的积分的函数 integral( f ) 来计算 f 在任何区间上的积分

Use a function integral( f ) which computes the integral of f over [0,1] to compute the integral of f over any interval

如何使用计算函数 f 在 [0,1] 上的积分的(假设的)例程 integral( f ) 来计算 f 在任何区间 [a,b] 上的积分?

如果我想更改积分区间,我会使用以下替换:

y = (x-a)/(b-a)

dy = (1/(b-a))dx

这意味着我现在可以计算 [0,1] 上的积分 f(y)*(b-a)dy 以获得与 [a,b] 上积分 f(x)dx 相同的结果,但是函数 integral() 接受一个参数 - 一个函数 - 我很难弄清楚如何使用我发现的替换来导出该函数。

您创建了一个新函数 g,它是原始函数 f 的适当缩放版本。

g(x) = f(a + x * (b - a))
// Now we have ...
// g(0) = f(a)
// g(1) = f(b)
// ... and the function between is linearly scaled

然后你把这个函数传给integral。结果需要按 (b - a).

缩放(因为步骤也已缩放)

理论到此为止,但在实践中,您只能在可以创建闭包时执行此操作,即使用来自其(词法)环境的一些数据来关闭的函数。 (或者,如果您有某种方法可以模拟它,例如某些 C 库中使用的附加 void * user_data 参数)

此外,由于您用 numerical-integration 标记了它,您需要考虑 integral 使用的步长可能适用于许多功能,但 scaled 步长可能太大,无法通过积分产生正确的结果。


Common Lisp 中的小例子:

;; from http://rosettacode.org/wiki/Numerical_integration#Common_Lisp
(defun left-rectangle (f a b n &aux (d (/ (- b a) n)))
  (* d (loop for x from a below b by d summing (funcall f x))))

(defun integral (f)
  (left-rectangle f 0 1 10))


(defun integral-range (f a b)
  (* (- b a) (integral #'(lambda (x) (funcall f (float (+ a (* x (- b a)))))))))

(defun test-fn (x) (* x 2))
(trace test-fn)

(let ((i (integral-range #'test-fn 3 9)))
  (format t "Result of numerical integration: ~a~%" i)
  (format t "Error of numerical integration: ~a~%" (abs (- i (- (* 9 9) (* 3 3))))))

You can see it in action,其中 "Trace" 输出显示评估测试函数的点。


这里是 C 版本,通过分配全局静态变量来模拟上述闭包:

#include <stdio.h>
#include <math.h>

// from http://rosettacode.org/wiki/Numerical_integration#C
double int_leftrect(double from, double to, double n, double (*func)())
{
   double h = (to-from)/n;
   double sum = 0.0, x;
   for(x=from; x <= (to-h); x += h)
      sum += func(x);
   return h*sum;
}

double integral(double (*func)()) {
    return int_leftrect(0, 1, 10, func);
}


static double from;
static double to;
static double (*fn)();
double scaled(double x) {
    return fn(from + x * (to - from));
}

double integral_range(double (*func)(), double a, double b) {
    from = a;
    to = b;
    fn = func;
    return integral(scaled) * (b - a);
}

double test_fn(double x) {
    double result = 2 * x;
    printf("TRACE: test_fn(%f) => %f\n", x, result);
    return result;
}

int main(void) {
    double result = integral_range(test_fn, 3, 9);
    double expected = (9 * 9) - (3 * 3);
    printf("result of numerical integration: %f\n", result);
    printf("error of numerical integration: %f\n", fabs(result - expected));
    return 0;
}

(In action)