игра брюс 2048
Главная / Программирование / Программирование / Тест 69

Программирование - тест 69

Упражнение 1:
Номер 1
Рассмотрим следующий фрагмент программы:

утверждение: A(x)
цикл пока B(x)
| инвариант: A(x)
| x := T(x)
конец цикла

Здесь через A(x) и B(x)
обозначены условия, зависящие от переменной x.
Какое условие выполняется по окончании цикла?

Ответ:

 (1) Условие (не A(x) и B(x)).  

 (2) Условие (A(x) и B(x)).  

 (3) Условие (A(x) и не B(x)).  

 (4) Условие (не A(x) и не B(x)).  


Номер 2
Выполняется ли инвариант цикла в процессе выполнения
тела цикла?

Ответ:

 (1) Да, выполняется.  

 (2) Не обязательно.  


Номер 3
Укажите, в какие моменты работы программы выполняется
инвариант цикла.

Ответ:

 (1) Перед первым выполнением тела цикла и после последнего выполнения тела цикла.  

 (2) Перед каждым выполнением тела цикла.  

 (3) Перед каждым выполнением тела цикла и после каждого выполнения тела цикла.  


Упражнение 2:
Номер 1
Пусть целочисленная переменная n
содержит некоторое положительное целое число.
Указать, что вычисляет следующая функция f(n):

int f(int n) {
    int s = 2; int k = 0;
    while (s <= n) {
        // Invariant: s == 2^(k+1)
        s *= 2; ++k;
    }
    return k;
}


Ответ:

 (1) Целую часть квадратного корня из n.  

 (2) Целую часть от log2 n.  

 (3) Целую часть кубического корня из n.  

 (4) Целую часть от en.  

 (5) Целую часть от 2n.  


Номер 2
Пусть целочисленная переменная n
содержит некоторое положительное целое число.
Указать, что вычисляет следующая функция f(n):

int f(int n) {
    int x = 1; int y = 4;
    while (y <= n) {
        // Invariant: y == (x+1)^2
        ++x;
        y += 2*x+1;
    }
    return x;
}


Ответ:

 (1) Целую часть от n/2;  

 (2) Целую часть квадратного корня из n.  

 (3) Целую часть от log2 n.  

 (4) Целую часть кубического корня из n.  

 (5) Целую часть от en.  

 (6) Целую часть от 2n.  


Номер 3
Пусть целочисленная переменная n
содержит некоторое положительное целое число.
Указать, что вычисляет следующая функция f(n):

int f(int n) {
    int s = 10; int k = 0;
    while (s <= n) {
        // Invariant: s == 10*(k+1)
        s += 10; ++k;
    }
    return k;
}


Ответ:

 (1) Целую часть частного n/10.  

 (2) Произведение 10*n.  

 (3) Целую часть десятичного логарифма log10 n.  

 (4) Целую часть кубического корня из n/10.  

 (5) Целую часть от 210*n.  


Упражнение 3:
Номер 1
Рассмотрим следующую функцию, аргументами которой
являются два целых неотрицательных числа:

int f(int m, int n) {
    int a = m, b = n;
    int p = 0;
    while (b != 0) {
        if (b%2 == 0) { // b четное
            b /= 2;
            a *= 2;
        } else { // b нечетное
            --b;
            p += a;
        }
    }
    return p;
}

Какое условие является инвариантом цикла?

Ответ:

 (1) Равенство ab p = mn  

 (2) Равенство a*b + p = m*n  

 (3) Равенство ba p = mn  

 (4) Равенство a/b + p = m*n  

 (5) Равенство a + b + p = m*n  


Номер 2
Рассмотрим следующую функцию, аргументами которой
являются два целых неотрицательных числа:

int f(int m, int n) {
    // дано: m >= 0 и n >= 0
    int a = m; int b = n;
    int c = 1;
    while (a != 0 && b != 0) {
        if (a%2 == 0 && b%2 == 0) {
            // a и b четные
            a /= 2; b /= 2;
            c *= 2;
        } else if (a%2 == 0) {
            // a четное, b нечетное
            a /= 2;
        } else if (b%2 == 0) {
            // a нечетное, b четное
            b /= 2;
        } else {
            // a и b нечетные
            if (a > b) {
                a -= b;
            } else {
                b -= a;
            }
        }
    } // end while
    return c*(a + b);
}

Какое условие является инвариантом цикла?
(Через НОД и НОК обозначены наибольший общий делитель и
наименьшее общее кратное.)

Ответ:

 (1) Равенство НОД(a, b) = НОД(m, n)*c.  

 (2) Равенство НОК(m, n) = c*(a + b).  

 (3) Равенство НОД(a,b)*c = НОД(m, n).  

 (4) Равенство НОД(a,b) = НОД(m, n)*c.  


Номер 3
Рассмотрим следующий фрагмент программы, вычисляющей
частное q и остаток r от деления
целых чисел a, b:

    // дано: целые числа a >= 0, b > 0
    int a, b;
    . . .
    int q = 0, r = a;
    int e = 1, m = b;
    while (r >= b) {
        if (2*m <= r) {
            e *= 2; m *= 2;
        } else if (m > r) {
            e /= 2; m /= 2;
        } else {
            // утверждение: m <= r && r < 2*m
            q += e; r -= m;
        }
    }
    // q и r - частное и остаток от деления a на b

Какое условие является инвариантом цикла?

Ответ:

 (1) Число e является степенью двойки, а также выполняются равенства a - q*b == r и m == e*b.  

 (2) Число e является степенью двойки, а также выполняются равенства a - q*m == r и m == e*b.  

 (3) Число e является степенью двойки, а также выполняются равенства a + q*b == r и m == e*b.  

 (4) Число e является степенью двойки, а также выполняются равенства a - q*m == r и m == e+b.  


Упражнение 4:
Номер 1
Какое утверждение является инвариантом для следующего
фрагмента программы (т.е. из справедливости утверждения
до выполнения фрагмента программы вытекает справедливость утверждения
после выполнения)? Предполагается, что значение переменной
n неотрицательно.

    double r, x; int n;
    . . .
    r *= x*x;
    r /= ((n+1)*(n+2));
    n += 2;


Ответ:

 (1) Утверждение r == xn/n!, где восклицательным знаком обозначен факториал числа n.  

 (2) Утверждение r == xn/((n+1)*(n+2)).  

 (3) Утверждение r == (x+n)/n!, где восклицательным знаком обозначен факториал числа n.  

 (4) Утверждение r == xn/(n+1)!.  


Номер 2
Какое утверждение является инвариантом для следующего
фрагмента программы (т.е. из справедливости утверждения
до выполнения фрагмента программы вытекает справедливость утверждения
после выполнения)? Предполагается, что n > 0.

    double r, x; int n;
    . . .
    r *= -x;
    r *= n/(n+1);
    ++n;


Ответ:

 (1) Утверждение r == (-1)n*xn/n!, где восклицательным знаком обозначен факториал числа n.  

 (2) Утверждение r == (-1)n-1*xn/n.  

 (3) Утверждение r == (-1)n+1*xn/n!, где восклицательным знаком обозначен факториал числа n.  

 (4) Утверждение r == (-1)n+1*xn/n.  


Номер 3
Какое утверждение является инвариантом для следующего
фрагмента программы (т.е. из справедливости утверждения
до выполнения фрагмента программы вытекает справедливость утверждения
после выполнения)? Предполагается, что
n не меньше k.
Восклицательным знаком обозначается операция вычисления факториала.

    int n, k, c;
    . . .
    c *= (n+1);
    c /= (n+1-k);
    ++n;


Ответ:

 (1) Утверждение c = n! / (k! * (n-k)!).  

 (2) Утверждение c = (n+k)! / (n! * (n-k)!).  

 (3) Утверждение c = (n-k)! / (k! * (n+k)!).  

 (4) Утверждение c = (n+k)! / (k! * (n-k)!).  


Упражнение 5:
Номер 1
Оценить сверху время работы (т.е. количество
выполнений тела цикла) алгоритма Евклида
вычисления наибольшего общего делителя двух целых чисел:

int gcd(int m, int n) {
    // дано: целые числа m, n, хотя бы одно отлично от нуля
    // надо: вычислить НОД пары (m, n)
    int a = m, b = n;
    while (b != 0) {
        // Invariant: НОД(a, b) == НОД(m, n)
        int r := a % b; // находим остаток от деления a на b
        a = b; b = r;   // заменяем пару (a, b) на (b, r)
    }
    return a;           // ответ = a
}


Ответ:

 (1) Время работы не больше, чем C*log2max(m, n), где C - некоторая константа (т.е. время пропорционально количеству цифр в двоичной или десятичной записи максимального из чисел m, n).  

 (2) Время работы не больше, чем C*r, где C - некоторая константа, r - квадратный корень из max(m, n) (т.е. время пропорционально квадратному корню из максимального числа).  

 (3) Время работы не больше, чем C*max(m, n), где C - некоторая константа (т.е. время пропорционально максимальному из чисел m, n).  


Номер 2
Оценить сверху время работы (т.е. количество
выполнений тела цикла) алгоритма быстрого возведения в степень:

int fastPow(double a, int n) {
    // дано: основание a и показатель степени n >= 0
    // надо: вычислить a в степени n
    double b = a, p = 1.0; int k = n;

    while (k > 0) {
        // Invariant: b^k * p == a^n
        if (k%2 == 0) {
            // k четное
            k /= 2;
            b *= b;
        } else {
            // k нечетное
            --k;
            p *= b;
        }
    }
    return p;
}


Ответ:

 (1) Время работы не больше, чем C*n, где C - некоторая константа (т.е. время пропорционально числу n).  

 (2) Время работы не больше, чем C*log2 n, где C - некоторая константа (т.е. время пропорционально количеству цифр в двоичной или десятичной записи числа n).  

 (3) Время работы не больше, чем C*r, где C - некоторая константа, r - квадратный корень из числа n (т.е. время пропорционально квадратному корню из n).  


Номер 3
Оценить сверху время работы (т.е. количество
выполнений тела цикла) алгоритма
приблизительного вычисления логарифма:

double myLog(double x, double a, double eps) {
    // дано: x > 0, a > 1, eps > 0
    // надо: вычислить log_a x с точностью eps
    double y = 0.0, z = x, t = 1.0;

    while (
        fabs(t) > eps ||
        x <= 1.0/a ||
        z >= a
    ) {
        // Invariant: a^y * z^t == x
        if (z >= a) {
            z /= a; y += t;
        } else if (z <= 1.0/a) {
            z *= a; y -= t;
        } else {
            z *= z; t /= 2.0;
        }
    }
    return y;
}


Ответ:

 (1) Время работы не больше, чем C*log2 [x+1], где C - некоторая константа, [x+1] - целая часть числа x+1 (т.е. время пропорционально количеству цифр в двоичной или десятичной записи целой части числа x).  

 (2) Время работы не больше, чем C*log2[x+1]*log2(1/eps), где C - некоторая константа, а квадратные скобки обозначают целую часть. Иначе говоря, время пропорционально количеству цифр в двоичной или десятичной записи целой части x, умноженному на требуемое количество значащих цифр в дробной части результата.  

 (3) Время работы не больше, чем C*log2[x+1] + log2(1/eps), где C - некоторая константа, а квадратные скобки обозначают целую часть. Иначе говоря, время пропорционально сумме количества цифр в двоичной или десятичной записи целой части x и требуемого количества значащих цифр в дробной части результата.  


Упражнение 6:
Номер 1
Пусть f(x) - целочисленная функция от целочисленного
аргумента. Определить,
содержит ли следующий фрагмент программы ошибку
(т.е. действительно ли тело цикла сохраняет инвариант):

// Программа корень функции
    int a, b, c;
    . . .
    // утверждение: a < b  && f(a)*f(b) <= 0
    // Значения функции на концах отрезка [a,b] разных знаков

    while (b - a > 1) {
        // Invariant: f(a)*f(b) <= 0
        // Делим отрезок [a, b] пополам
        c = (a + b)/2; // c - целая часть (a+b)/2
        if (f(a) * f(c) < 0) {
            b = c;     // выбираем левую половину отрезка
        } else {
            a = c;     // выбираем правую половину
        }
    }

    // утверждение: a == b-1  &&
    //              f(a)*f(b) <= 0


Ответ:

 (1) Ошибки нет, фрагмент программы корректный.  

 (2) Фрагмент программы содержит ошибку.  


Номер 2
Пусть a - целочисленный массив размера n
(индекс элементов меняется от 0 до n-1),
элементы которого строго возрастают:
a[0] < a[1] <... < a[n-1].
Определить, содержит ли следующий фрагмент программы ошибку
(т.е. действительно ли тело цикла сохраняет инвариант):

// Программа Поиск
    int n; int *a;
    . . .
    // дано: целое n;
    //       целочисленный массив a[n],
    //           элементы которого строго возрастают
    //           a[0] < a[1] < ... < a[n-1]
    // надо: найти элемент x в массиве
    int x;          // искомый элемент
    . . .           // рассматриваются исключительные случаи

    // общий случай
    // утверждение: a[0] < x  &&  x <= a[n-1];
    int b = 0; int e = n - 1;

    while (e - b > 1) {
        Invariant: a[b] < x  &&  x <= a[e]
        int c := (a + b)/2; // c - целая часть (a+b)/2
        if (x < a[c]) {
            e = c;  // выбираем левую половину отрезка
        } else {
            b = c;  // выбираем правую половину
        }
    }

    // утверждение: b == e - 1   &&
    //              a[b] < x  &&  x <= a[e]


Ответ:

 (1) Ошибки нет, фрагмент программы корректный.  

 (2) Фрагмент программы содержит ошибку.  


Номер 3
Пусть f(x) - вещественная функция функция
от вещественного
аргумента. Определить,
содержит ли следующий фрагмент программы ошибку
(т.е. действительно ли тело цикла сохраняет инвариант):

// Программа корень функции
    double a, b, c;
    double eps = 0.000001;
    . . .
    // утверждение: a < b  && f(a)*f(b) <= 0.0
    // Значения функции на концах отрезка [a, b] разных знаков

    while (b - a > eps) {
        // Invariant: f(a)*f(b) <= 0.0
        // Делим отрезок [a, b] пополам
        c = (a + b)/2.0; // c - середина отрезка [a, b]
        if (f(a) * f(c) < 0.0) {
            b = c;     // выбираем левую половину отрезка
        } else {
            a = c;     // выбираем правую половину
        }
    }

    // утверждение: b - a <= eps  &&
    //              f(a)*f(b) <= 0.0


Ответ:

 (1) Ошибки нет, фрагмент программы корректный.  

 (2) Фрагмент программы содержит ошибку.  




Главная / Программирование / Программирование / Тест 69