Лекции по СЯП
Описание файла
Документ из архива "Лекции по СЯП", который расположен в категории "". Всё это находится в предмете "семантика языков программирования" из 6 семестр, которые можно найти в файловом архиве НИУ «МЭИ» . Не смотря на прямую связь этого архива с НИУ «МЭИ» , его также можно найти и в других разделах. Архив можно найти в разделе "лекции и семинары", в предмете "семантика языков программирования" в общих файлах.
Онлайн просмотр документа "Лекции по СЯП"
Текст из документа "Лекции по СЯП"
СЕМАНТИКА ПРОГРАММ
Формальная семантика программ – это область теоретической информатики, занимающаяся математическим изучением моделей вычислений и смысла программ.
Имеется много подходов к формальной семантике программ. Эти подходы можно отнести к трем классам:
▪ Операционная семантика. Эта семантика связана с интерпретацией предложений программы как процесса вычисления на абстрактных автоматах или вывода в формальных системах;
▪ Денотационная семантика. Эта семантика связана с «компиляцией» программ в математических структурах (а не в других компьютерных языках, как это делается при обычной компиляции);
▪ Аксиоматическая семантика. Эта семантика связывает с предложениями программы формулы в подходящей логике, которые описывают определяемые этими предложениями эффекты. Эти формулы используются затем для вывода (дедукции) различных свойств программы.
Замечание. На самом деле эта классификация не является четкой: часто используется комбинация этих семантик.
1. ОПЕРАЦИОННАЯ СЕМАНТИКА
Операционная семантика программы выражается в терминах преобразований состояний вычисления, выполняемого этой программы. Рассмотрим примеры.
-
Примеры вычислений, определяемых программой.
Программы для алгоритма Эвклида
Алгоритм Эвклида – это древнейший алгоритм для нахождения наибольшего общего делителя двух натуральных чисел.
Замечание. Эвклид дал формулировку этого алгоритма в геометрии в виде метода для нахождения общей меры двух отрезков.
Обозначим:
▪ N – множество натуральных чисел: 0, 1, 2, 3,…;
▪ x|y df x – делитель у ( u) xu=y (x, y, u N);
▪ нод(х,у) = max{z | z|x, z|y} (x, y, z N),
▪ x mod y – остаток от деления х на y (x, y N),
▪ |_z_| – ближайшее целое к вещественному числу z, т.е.
Очевидно, что
А. Программа для алгоритма Эвклида в языке блок-схем.
Начало
– x<y? +
(x,y) := (y,x)
1 2
(x,y) := (y, x mod y)
+ 3 у =0? –4
return x
5
Конец
Рис.1
В этой программе входными переменными считаются х и у. Эти же переменные считаются рабочими переменными. Переменная х также считается выходной переменной.
Состояние вычисления по этой программе включает значения рабочих переменных и номер выполняемого в данный момент предложения программы. Кроме того, начальные состояния включают значения входных переменных, а заключительные состояния – значения выходной переменной. В число состояний также зачислим состояние остановки, которое обозначим восклицательным знаком «!». Таким образом множество StateР всех возможных состояний программы Р состоит из:
▪ начальных (входных) состояний (х,у), где х,у N;
▪ промежуточных состояний (j,x,y), где j {1,2,3,4,5} x,y N;
▪ заключительных (выходных) состояний х N;
▪ состояния остановки «!».
Каждый из операторов программы Р определяет преобразование состояний ТР: StateP StateP (которое будем обозначать просто Т, когда ясно о какой программе идет речь):
Т(x,y) = (1,x,y);
Τ(1,x,y) = (2,x,y), если х<y;
Τ(2,x,y) = (3,y,x);
Τ(3,x,y) = (5,x,y), если у=0;
Τ(4,x,y) = (y, x mod y);
Τ(5,x,y) = х;
Т(х) = !
Процесс вычисления можно описать как итерацию применения преобразования T = TP. Точнее, для входного состояния (a,b) вычисление – это последовательность состояний
CompP(a,b): σ0 = (a,b), σ1=T(σ0), σ2=T(σ1),…, σn= T(σn-1), T(σn) = c,
Заключительным состоянием является (если программа Р корректна) наибольший общий делитель чисел a и b: c = нод(a,b).
Рассмотрим пример вычисления нод(28,72) по программе Р:
(28,72),
T(28,72) = (1,28,72),
T(1,28,72) = (2,28,72),
T(2,28,72) = (3,72,28),
T(3,72,29) = (4,72,28),
T(4,72,28) = (3,28,16),
T(3,28,16) = (4,16,12),
T(4,16,12) = (3,12,4),
Τ(3,12,4) = (4,4,0),
Τ(4,4,0) = (5,4,0),
Τ(5,4,0) = 4,
Т(4) = !.
Таким образом, получаем, что нод(28,72) = 4.
Итак, имеем следующую последовательность состояний, определяющую вычисление по программе Р для входа х = 28, у =72:
(28,72) |– (1,28,72) |– (2,28,72) |– (3,72,28) |– (4,72,28) |– (3,28,16)
|– (4,16,12) |– (3,12,4) |– (4,4,0) |– (5,4,0) |– 4 |– ! (1.1)
Здесь символ |– обозначает бинарное отношение, определяемое преобразованием τ :
σ |– τ T(σ) = τ (σ, τ StateP).
Замечание. Ясно, что отношение |– обладает свойством однозначности:
Это означает детерминированность программы Р для алгоритма Эвклида. В общем случае отношение |– может быть неоднозначным, что означает недетерминированность программы.
Последовательность (1.1) дает пример вычисления по программе Р для алгоритма Эвклида. Это вычисление было выполнено для входа (28,72).
Пусть Р – произвольная программа в некотором языке и StateP
Обозначим через |–* транзитивное и рефлексивное замыкание бинарного отношения, т.е.
σ |–* τ ( σ1, σ2…., σk StateP) σ = σ1 |– σ2 |– … |– σk = τ, σ |–* σ
для всех σ и τ.
Б. Программа для алгоритма Эвклида в языке с оператором while
Q: if x<y then (x,y) := (y,x) else skip;
while not y=0 do (x,y) := (y,x mod y) od;
return x
Обозначим:
a: (x, y) := (y, x),
b: skip,
c: (x, y) := (y, x mod y).
d: return x,
e: if x < y then (x, y) := (y, x) else skip,
f : while not y=0 do (x, y) := (y, x mod y) od,
Множеством возможных состояний программы Р является
{(p, u, v) | u, v N, p {a, b, c, d, e, f} } N {!}.
Программа Q определяет следующее преобразование Т состояний:
T(u, v) = (е, u, v);
T(е, u, v) = (a, u, v), если u < v;
T(e, u, v) = (b, u, v), если u v;
T(a, u, v) = (f, v, u);
T(b, u, v) = (f, u, v);
T(f, u, v) = (f, v, u mod v), если v 0;
T(f,u,v) = (d,u,v), если v=0;
T(d, u, v) = u;
T(u) = !
Рассмотрим пример вычисления по программе Р, взяв в качестве входа пару чисел (28,72). Применяя последовательно преобразование Т, получим
(28, 72),
T(28, 72) = (e, 28, 72),
T(e, 28, 72) = (a, 28, 72),
T(а, 28, 72) = (f, 72, 28),
T(f,72,28) = (f,28,16),
T(а, 28, 16) = (f, 16, 12),
T(f, 28, 16) = (f, 16, 12),
T(f, 16, 12) = (f, 12, 4),
T(f, 12, 4) = (f, 4, 0),
T(f, 4, 0) = (d, 4, 0),
T(d, 4, 0) = 4,
T(4) = !.
Таким образом, получаем следующую последовательность состояний, определяющую вычисление по программе Р:
(28, 72) |– (e, 28, 72) |– (a, 28, 72) |– (f, 72, 28) |– (f, 28, 16)
|– (f,16,12) |– (f, 12, 4) |– (f, 4, 0) |– (d, 4, 0) |– 4 |– !
Таким образом Процесс вычисления можно описать как итерацию применения преобразования T = TP. Точнее, для входного состояния (a, b) вычисление – это последовательность состояний
CompP(a, b): σ0 = (a, b), σ1= T(σ0), σ2= T(σ1),…, σn= T(σn-1),
T(σn-1) = c, T(c)=!
Заключительным состоянием является (если программа Р корректна) наибольший общий делитель чисел a и b: c = нод(a ,b).
-
Ханойская башня
«Ханойская башня» - это игра, состоящая в следующем. Имеется три колышка и 8 дисков различного размера. В начале игры все диски надеты на первый колышек так, как это показано на рис.2. Таким образом, имеем башню, в которой диски лежат по возрастанию их размеров. Цель игры – перенести колышки так, чтобы башня оказалась на втором колышке. При этом должны соблюдать следующие правила игры:
▪ Один ход игры состоит из переноса одного верхнего диска с одного колышка на другой;
▪ Не разрешается класть диск большего размера на диск меньшего размера.
Рис.2
Оказывается, что кратчайшее (по числу шагов) решение игры составляет 28–1 = 127 ходов. В общем случае, когда имеются n дисков , кратчайшее решение игры включает 2n–1. Например, в случае трех дисков игра имеет следующее решение:
1-й ход: Перенести диск с первого колышка на второй;
2-й ход: Перенести диск с первого колышка на третий;
3-й ход: Перенести диск со второго колышка на третий;
4-й ход: Перенести диск с первого колышка на второй;
5-й ход: Перенести диск с третьего на первый;
6-й ход: Перенести диск с третьего на второй;
7-й ход: Перенести диск со второго колышка на третий
s0
s1
s2
s3
s4
s5
s6