- •21.11.12 Лекция 10
- •7. Технология предикатного программирования 7.6. Разработка и верификация программ стандартных функций
- •Иллюстрация методов разработки и верификации
- •Разработка программы вычисления целочисленного квадратного корня
- •Построение (синтез) программы для предиката isqrt
- •Построение программы для предиката sq0
- •Более эффективная версия программы isqrt
- •Алгоритм вычисления целочисленного квадратного корня через двоичное разложение
- •Спецификация обобщающей задачи:
- •Оптимизации программы предиката sq2
- •Синтез программы sq3
- •Трансформация программы isqrt1
- •Трансформация программы isqrt1 (прод1.)
- •Трансформация программы isqrt1 (прод2.)
- •Преобразования императивной программы
- •Доказательство формул корректности на PVS
- •Доказательство формул корректности (пр1)
- •Доказательство формул корректности (пр2)
- •Доказательство формул корректности (пр3)
- •Теория bit_nat
- •Итоги
- •Алгоритм вычисления целой части плавающего числа
- •Представим теорию main для определения предиката floor.
- •floor_val: THEORY BEGIN
- •В соответствии с правилом FC1 для первой альтернативы условного оператора генерируется цель:
- •В программе, находящейся в файле fast_floor.cpp обнаружено две ошибки:
- •8.Язык, технология
- •8.1. Класс объектно-ориентированных программ.
- •class D { invariant ID(s);
- •3. Класс простых процессов.
- •Языковые средства описания процесса
- •Декомпозиция процессов
- •Декомпозиция с одним внутренним состоянием:
- •stop
- •Декомпозиция без внутренних состояний:
- •Пример 1. Гадание на кофейных зернах
- •2.Электронные часы с будильником
- •class Часы { nat hours; nat minutes;
Оптимизации программы предиката sq2
Ввыражении q + 2^(k-1) заменим “+” побитовой операцией “or”. Чтобы обеспечить корректность такой замены, необходимо доказать лемму:
or_eq_plus: lemma k > 0 & k < p & mod(q, 2^k) = 0 & q < 2^p (q or 2^(k - 1)) = q + 2^(k - 1)
Необходимое условие mod(q, 2^k) = 0 проще обеспечить включением его в предусловие.
Упростить вычисление n < (q + 2^(k-1))^2
(q + 2^(k-1))^2 = q^2 + 2^((k-1)*2) + q * 2^k Тогда условие n < (q + 2^(k-1))^2 эквивалентно:
n - q^2 < 2^((k-1)*2) + q * 2^k Обозначим y = n - q^2.
Синтез программы sq3
Синтезируем программу с указанными оптимизациями sq2: formula P_sq3(nat n, p, k, q, y) =
P_sq2(n, p, k, q) & y = n - q^2 & mod(q, 2^k) = 0; isqrt1(nat n, p: nat s) pre P_sqp(n, p)
{ sq3(n, p, p, 0, n: s) } post Isqrt(n, s);
sq3(nat n, p, k, q, y: nat s) pre P_sq3(n, p, k, q, y) { if (k = 0) s = q
else { nat t = 2^((k-1)*2) + q * 2^k;
if (y < t) sq3(n, p, k - 1, q , y: s)
else sq3(n, p, k - 1, q or 2^(k-1), y – t : s)
}
} post Isqrt(n, s);
Трансформация программы isqrt1
Этап 1. Склеивание переменных: sq3: n y; s q; sq3(nat n, p, k, s, n: nat s)
{ if (k = 0) s = s
else { nat t = 2^((k-1)*2) + s * 2^k;
if (n < t) sq3(n, p, k – 1, s, n: s)
else sq3(n, p, k - 1, s or 2^(k-1), n – t : s) }
}
Этап 2. Замена хвостовой рекурсии циклом. sq3(nat n, p, k, s, n: nat s)
{ M: if (k = 0) s = s
else { nat t = 2^((k-1)*2) + s * 2^k;
if (n < t) { |n, p, k, s, n| = |n, p, k – 1, s, n|; goto M }
else {|n, p, k, s, n| = |n, p, k-1, s or 2^(k-1), n - t|; goto M}}
}
Трансформация программы isqrt1 (прод1.)
Этап 2a. Оформление цикла и раскрытие мульти-присваиваний
sq3(nat n, p, k, s, n: s) |
|
{for (;;) { if (k = 0) break; |
|
nat t = 2^((k-1)*2) + s * 2^k; |
|
if (n < t) k = k – 1 |
|
else { s = s or 2^(k-1); k = k – 1; n = n – t } |
} |
}
Этап 2б. Оформление цикла и упрощения sq3(nat n, p, k, s, n: s)
{ for ( ; k = 0; k = k – 1) {
nat t = 2^((k-1)*2) + s * 2^k;
if (n >= t) { n = n – t ; s = s or 2^(k-1); }
}
}
Трансформация программы isqrt1 (прод2.)
isqrt1(nat n, p: nat s) { sq3(n, p, p, 0, n: s) }
Этап 3. Подстановка определения предиката на место вызова isqrt1(nat n, p: nat s) {
nat k; |n, p, k, s, n| = |n, p, p, 0, n|; for ( ; k = 0; k = k – 1) {
nat t = 2^((k-1)*2) + s * 2^k;
if (n >= t) { n = n – t ; s = s or 2^(k-1); } }
}
Программа на императивном расширении языка P nat n, p; nat s = 0;
for (nat k = p ; k = 0; k = k – 1) {
nat t = 2^((k-1)*2) + s * 2^k;
if (n >= t) { n = n – t ; s = s or 2^(k-1); }
}
Преобразования императивной программы
nat n, p; nat s = 0;
for (nat k = p; k = 0; k = k - 1) {
|
nat t = 2^((k-1)*2) + s * 2^k; |
|
if (n >=t) { n = n – t; s = s or 2^(k-1); } |
} |
Введем макрос для тела цикла: |
sq(k) = { t = 2^((k-1)*2) + s * 2^k; if (n >=t) { n = n – t; s = s or 2^(k-1); } }
Проведем развертку цикла. Получим:
nat n, p; nat s = 0;
sq(p); sq(p – 1); …; sq(2); sq(1)
Проведем подстановку тела для sq(p) и sq(1). Получим программу, тождественную исходной:
sq(k){ t = 2^((k-1)*2) + s * 2^k; if (n >=t) { n = n – t; s = s or 2^(k-1); } } nat n, p;
nat s = 0;
if (n >= 2^((p-1)*2)) { n = n – 2^((p-1)*2); s = 2^(p-1); }
sq(p – 1); …; sq(2);
if (n >= s * 2) s = s or 1
static const uint32_t small_limit = 17;
static const uint32_t small_sqrts[small_limit] =
// |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 11 12 13 14 15 16 |
{0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4}; |
|||||||||||
#define sqrtBit(k) |
|
|
\ |
|
|
||||||
|
t = s + (1UL << (k - 1)); |
|
|
||||||||
t <<= k + 1;
if (_n >= t) {_n -= t; s |= 1UL << k;}
uint32_t os::isqrt(uint32_t _n) { if (_n < small_limit)
return small_sqrts[_n]; uint32_t s = 0UL;
if (_n >= 1UL<<30) { _n -= 1UL<<30; s = 1UL<<15; } uint32_t t;
sqrtBit(14); sqrtBit(13); sqrtBit(12); sqrtBit(11); sqrtBit(10); sqrtBit(9); sqrtBit(8); sqrtBit(7); sqrtBit(6); sqrtBit(5);
sqrtBit(4); sqrtBit(3); sqrtBit(2); sqrtBit(1); if (_n > s<<1)
s |= 1UL; return s;
}
Доказательство формул корректности на PVS
isqrt : THEORY BEGIN
IMPORTING fl, reals@sqrt, reals@sq, bit_nat n, s, x, k, m: VAR nat
Isqrt(n, s): bool = s = floor(sqrt(n))
Isqrt_eq: LEMMA Isqrt(n, s) IFF s^2 <= n & n < (s + 1)^2
Isqrt_uniq: LEMMA Isqrt(n, s) & Isqrt(n, m) IMPLIES s = m
Isqrt_total: LEMMA EXISTS s: Isqrt(n, s)
P_sq0(x, k): bool = k^2 <= x
Isqrt_fb1: LEMMA Isqrt(x, s) IMPLIES P_sq0(x, 0) & Isqrt(x, s)
e(x, k): nat = IF x<(k + 1)^2 THEN 0 ELSE x - k^2 ENDIF sq0_rec: LEMMA P_sq0(x, k) & Isqrt(x, m) IMPLIES
IF x < (k + 1)^2 THEN m = k
ELSE e(x, k+1) < e(x, k) & P_sq0(x, k+1) & Isqrt(x, m) ENDIF
Доказательство формул корректности (пр1)
P_sq1(x, y, k, d: nat): bool = k^2 <= x & d = 2 * k + 1 & y = x - k^2
Isqrt1_fb1: LEMMA Isqrt(x, s) IMPLIES P_sq1(x, x, 0, 1) & Isqrt(x, s) sq1_rec: LEMMA FORALL (x, y, k, d, m: nat):
P_sq1(x, y, k, d) & Isqrt(x, m) IMPLIES IF y < d THEN m = k
ELSE e(x, k+1) < e(x, k) &
P_sq1(x, y - d, k + 1, d + 2) & Isqrt(x, m) ENDIF
P_sqp(n, p: nat): bool = p > 0 & n < 2^(2*p)
P_sq2(n, p, k, q: nat): bool =
P_sqp(n, p) & k <= p & q^2 <= n & n < (q + 2^k)^2
p: VAR nat
Isqrt2_fb1: LEMMA P_sqp(n, p) & Isqrt(n, s) IMPLIES P_sq2(n, p, p, 0) & Isqrt(n, s)
e2(k: nat): nat = k
Доказательство формул корректности (пр2)
sq2_rec: lemma FORALL (n, p, k, q, s: nat): P_sq2(n, p, k, q) & Isqrt(n, s) IMPLIES
IF k = 0 THEN s = q
ELSIF n < (q + 2^(k-1))^2 THEN
e2(k-1) < e2(k) & P_sq2(n, p, k-1, q) & Isqrt(n, s) ELSE e2(k-1) < e2(k) & P_sq2(n, p, k-1, q + 2^(k-1)) & Isqrt(n, s) ENDIF
P_sq3(n, p, k, q, y: nat): bool =
P_sq2(n, p, k, q) & y = n - q^2 & mod(q, 2^k) = 0
p_2_2: LEMMA (2^p)^2 = 2^(2*p)
Isqrt3_fb1: LEMMA P_sqp(n, p) & Isqrt(n, s) IMPLIES
P_sq3(n, p, p, 0, n) & Isqrt(n, s)
