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>>;
};
};