Алгоритмическая сложность
Говорят, что если оценка есть или или … где константа, то алгоритм называется полиномиальным (если показатель степени небольшой, то ещё и называется эффективным).
Ну, например, простейшая сортировка массива методом выбора имеет сложность (Православные сортировки имеют сложность ) Что это означает? Что если мы будем увеличивать длину входа в раз, то количество операций, выполняемых компьютером, будет увеличиваться в раз, где некая константа. Например, если увеличить в 5, 10, 20, 30, 40 раз, а то количество операций будет увеличиваться в раз.
А вот если алгоритм имеет сложность или вместо 2 любое другое константное основание, то его называют экспоненциальным (пример любой переборный алгоритм). Тогда, даже если то при увеличении длины входа в 5, 10, 20, 30, 40 раз количество операций будет увеличиваться соответственно в раз. Что называется, почувствуйте разницу. Теперь, что такое вообще длина входа и количество операций, в чём их мерить? это биты, символы или количество строк? А количество операций это ассемблерные команды, количество шагов Машины Тьюринга, операторы C или что-то ещё? А вот в том-то и дело, что неважно, ведь у нас оценка не абсолютная, а асимптотическая, нам важно лишь, как меняется относительная скорость работы алгоритма по сравнению с относительным изменением количества входных данных, поэтому все эти конкретные коэффициенты попадут в это Главное, какие команды мы обзовём элементарными. Ясно, что какой-нибудь метод list.sort() не тянет на элементарную. Как получить эту оценку? Правильный ответ подумать головой. И решить задачку: во сколько раз увеличится количество операций при увеличении длины входа в 10, 20, 30, 40 раз? и увидеть эту функцию Иногда придётся доказать теорему. На практике обращают внимание на количество итераций циклов, на уровень вложенности циклов, и на вызовы функций, зависящих от n. Простой цикл for (int i = 0; i < n; i++) {...} (Си) даёт оценку двойной цикл for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {...} (Си) уже если их тела тривиальны и не зависят от Если в теле циклов вызываются функции, которые сами по себе тоже зависят от то это добавляет сложности и это тоже надо учитывать.
Тесты
Классификация по степени изолированности:
- Unit test. Модульное тестирование - проверка на корректность отдельных модулей исходного кода, “первый бастион” на борьбе с багами. Идея в тестировании каждой нетривиальной функции. Недостаток сложно подобрать тесты для каждой ветви программы, выдерживает ли результат точность; качество моделирования определяется “на глаз”. Примеры тестов:
- Пустая картинка должна иметь размеры 0×0 и не выделять памяти.
- Создание пользователя с пустым именем должно вызывать исключение.
- Удаление элемента из середины списка должно уменьшать его размер на единицу.
- Генератор паролей должен создавать строку строго заданной длины.
- Интерполяция линейной функции в точках исходной сетки должна возвращать исходные значения.
- Перевод вектора в другую систему координат и обратно равен начальному вектору.
- Скалярное произведение двух перпендикулярных векторов должно возвращать ноль.
- Нормализация нулевого вектора должна вызывать исключение.
- Один шаг интегрирования для тела под действием постоянной силы должен давать приращение скорости
- Integration test. Интеграционное тестирование отдельные программные модули объединяются и тестируются в группе.
- Моделирование не запускается, если параметры нефизичны.
- System test. Проверяют работу всей программы как чёрного ящика на реалистичных сценариях.
- Запуск всей программы с одинаковым seed для генератора случайных начальных условий должен приводить к бит-в-бит идентичным выходным файлам за два прохода.
- При моделировании сохраняется полная энергия / период колебаний равен аналитическому.
- Проверка устойчивости и точности метода при вариации шага по времени.
Классификация по заданию строения системы:
- Static test. Статическое тестирование проверка инструментов кода без запуска, проверка документации.
- Dynamic test. Динамическое тестирование запуск кода для проведения проверок. Здесь можно полагаться на физический смысл описываемых процессов, законы сохранения. Виды:
- White-Box test. Тестирование белого ящика тестирование ветвей, маршрутов, операторов.
- Black-Box test. Тестирование чёрного ящика метод тестирования программы без использования знания о внутреннем устройстве объекта. Примеры:
- Эквивалентное разбиение: «Целое число принимает значение от 0 до 999», «Первый символ должен быть заглавным».
- Анализ граничных значений. Если входные значения должны быть в интервале проверяем
- Анализ причинно-следственных связей.
- Предположение об ошибке (в значительной степени основан на интуиции). Идея метода состоит в том, чтобы составить список, который перечисляет возможные ошибки и ситуации, в которых эти ошибки могли проявиться.
Другие тесты:
- Regression test. Регрессионное тестирование проверка того, как код работает после внесённых изменений.
- Mutation test. Мутационное тестирование небольшие изменения кода программы. Состоит в выборе мутирующих операторов и применения их одного за другим к каждому фрагменту исходного кода программы. Мутирующим оператором называется правило преобразования исходного кода. Например:
- Удалить оператор программы.
- Заменить каждое логическое выражение на логическую константу «истина» или «ложь».
- Заменить каждую арифметическую операцию на другую. Например,
+на*. - Заменить каждую логическую операцию на другую. Например,
>на>=.