1.6.4. ПРИМЕР: ПРОГРАММА ДИФФЕРЕНЦИРОВАНИЯ

Опишем функцию, которая будет выполнять символьное дифференцирование формул [Хен 83]. Чтобы не загромождать изложение мы будем рассматривать только простые формулы, в которые входят целые числа, переменные, а также операции + и *, хотя обобщить рассмотрение на случай более сложных формул не составило бы большого труда.

Будем обозначать через x и y произвольные переменные, через i - произвольное целое число, через e - произвольную формулу, а через Dx(e) - результат дифференцирования e по x. Тогда правила дифференцирования можно записать в виде

Dx(x) = 1

Dx(y) = 0 (где y не равно x)

Dx(i) = 0

Dx(e1 + e2) = Dx(e1) + Dx(e2)

Dx(e1 * e2) = e1 * Dx(e2) + e2 * Dx(e1)

Прежде чем писать программу дифференцирования, нужно выбрать для формул представление в виде объектных выражений. Обозначим через [e] представление формулы e. Выберем следующее представление

[x] = x

[i] = i

[e1 + e2] = (Sum [e1] [e2])

[e1 * e2] = (Prod [e1] [e2])

Теперь не составляет труда определить функцию Diff, первым аргументом которой является переменная, по которой надо дифференцировать, а вторым аргументом - формула, подлежащая дифференцированию. Результатом работы является продифференцированная формула.

$func Diff sX tE = tE;

Diff sX tE =

tE :

{

sX = 1;

sY = 0;

(s.Oper t.E1 t.E2) =

<Diff sX tE1> :: t.DxE1,

<Diff sX tE2> :: t.DxE2,

s.Oper :

{

Sum = (Sum t.DxE1 t.DxE2);

Prod = (Sum (Prod t.E1 t.DxE2) (Prod t.E2 t.DxE1));

};

};

Это определение функции Diff страдает очевидным недостатком: формулы, которые получаются в результате дифференцирования, содержат слишком много частей, которые можно сократить. Например

DX(3*(X*X)+5) = (3*((X*1)+(X*))+(X*X)*0)+0

в соответствии с приведенными выше правилами дифференцирования. Между тем, после очевидных упрощений эту формулу можно привести к виду

3*(X+X)

Для этого достаточно применить к формуле следующие правила преобразования:

0 + e2 ==> e2

e1+ 0 ==> e1

0 * e2 ==> 0

e1* 0 ==> 0

1 * e2 ==> e2

e1* 1 ==> e1

(Более сложные преобразования мы не рассматриваем, чтобы не загромождать изложения.)

Существует два способа реализовать эти упрощения. Можно сначала построить результат дифференцирования полностью, а затем анализировать его, пытаясь сделать упрощения. Другой способ - делать упрощения сразу же, в процессе дифференцирования. Мы поступим именно так.

Определим функции Sum и Prod. Эти функции будут получать на входе две формулы, и выдавать формулу, которая является их суммой или произведением соответственно. При этом будут сразу же делаться упрощающие преобразования.

$func Sum t1 t2 = t;

$func Prod t1 t2 = t;

Sum

{

0 t2 = t2;

t1 0 = t1;

t1 t2 = (Sum t1 t2);

};

Prod

{

0 t2 = 0;

1 t2 = t2;

t1 0 = 0;

t1 1 = t1;

t1 t2 = (Prod t1 t2);

};

Теперь переделаем определение функции Diff, вставив в соответствующие места вызовы функций Sum и Prod.

Diff sX tE =

tE :

{

sX = 1;

sY = 0;

(s.Oper t.E1 t.E2) =

<Diff sX tE1> :: t.DxE1,

<Diff sX tE2> :: t.DxE2,

s.Oper :

{

Sum = <Sum t.DxE1 t.DxE2>;

Prod = <Sum <Prod t.E1 t.DxE2> <Prod t.E2 t.DxE1>>;

};

};