% =============================================== % ТЕСТЫ ДЛЯ LAB9 TASK2 % Автоматические тесты всех предикатов % =============================================== % Запуск всех тестов run_tests :- write('=== ЗАПУСК АВТОМАТИЧЕСКИХ ТЕСТОВ TASK2 ==='), nl, test_digit_product, test_max_digit_not_div3, test_divisor_count, test_recursion_equivalence, test_edge_cases, test_performance, write('=== ВСЕ ТЕСТЫ TASK2 ЗАВЕРШЕНЫ ==='), nl. % =============================================== % ТЕСТЫ ДЛЯ ПРОИЗВЕДЕНИЯ ЦИФР % =============================================== test_digit_product :- write('--- Тестирование произведения цифр ---'), nl, % Тест базового случая (digit_product_up(0, 1) -> write('✓ digit_product_up(0,1) - ПРОЙДЕН') ; write('✗ digit_product_up(0,1) - ПРОВАЛЕН')), nl, (digit_product_down(0, 1) -> write('✓ digit_product_down(0,1) - ПРОЙДЕН') ; write('✗ digit_product_down(0,1) - ПРОВАЛЕН')), nl, % Тест известных значений TestCases = [ (123, 6), % 1*2*3 = 6 (456, 120), % 4*5*6 = 120 (789, 504), % 7*8*9 = 504 (102, 0), % 1*0*2 = 0 (555, 125), % 5*5*5 = 125 (1, 1), % 1 = 1 (9, 9) % 9 = 9 ], forall(member((N, Expected), TestCases), test_digit_product_case(N, Expected)), % Тест эквивалентности рекурсий test_digit_product_equivalence([0, 1, 12, 123, 1234, 5555, 102, 9876]), nl. test_digit_product_case(N, Expected) :- digit_product_up(N, P1), digit_product_down(N, P2), write('Произведение цифр '), write(N), write(': up='), write(P1), write(', down='), write(P2), write(', ожидалось='), write(Expected), ((P1 =:= Expected, P2 =:= Expected) -> write(' ✓') ; write(' ✗')), nl. test_digit_product_equivalence([]). test_digit_product_equivalence([N|Rest]) :- digit_product_up(N, P1), digit_product_down(N, P2), (P1 =:= P2 -> write('✓ Произведения цифр '), write(N), write(' эквивалентны') ; write('✗ Произведения цифр '), write(N), write(' НЕ эквивалентны')), nl, test_digit_product_equivalence(Rest). % =============================================== % ТЕСТЫ ДЛЯ МАКСИМАЛЬНОЙ ЦИФРЫ НЕ ДЕЛЯЩЕЙСЯ НА 3 % =============================================== test_max_digit_not_div3 :- write('--- Тестирование максимальной цифры не делящейся на 3 ---'), nl, % Тест базового случая (max_digit_not_div3_up(0, -1) -> write('✓ max_digit_not_div3_up(0,-1) - ПРОЙДЕН') ; write('✗ max_digit_not_div3_up(0,-1) - ПРОВАЛЕН')), nl, (max_digit_not_div3_down(0, -1) -> write('✓ max_digit_not_div3_down(0,-1) - ПРОЙДЕН') ; write('✗ max_digit_not_div3_down(0,-1) - ПРОВАЛЕН')), nl, % Тест известных значений TestCases = [ (123, 2), % цифры: 1,2,3 -> не дел. на 3: 1,2 -> макс: 2 (456, 5), % цифры: 4,5,6 -> не дел. на 3: 4,5 -> макс: 5 (789, 8), % цифры: 7,8,9 -> не дел. на 3: 7,8 -> макс: 8 (369, -1), % цифры: 3,6,9 -> все дел. на 3 -> -1 (147, 7), % цифры: 1,4,7 -> не дел. на 3: 1,4,7 -> макс: 7 (1, 1), % цифра: 1 -> не дел. на 3: 1 -> макс: 1 (39, -1), % цифры: 3,9 -> все дел. на 3 -> -1 (12457, 7), % цифры: 1,2,4,5,7 -> не дел. на 3: 1,2,4,5,7 -> макс: 7 (36960, -1) % цифры: 3,6,9,6,0 -> все дел. на 3 -> -1 ], forall(member((N, Expected), TestCases), test_max_digit_not_div3_case(N, Expected)), % Тест эквивалентности рекурсий test_max_digit_not_div3_equivalence([0, 123, 456, 369, 147, 12457, 98765]), nl. test_max_digit_not_div3_case(N, Expected) :- max_digit_not_div3_up(N, M1), max_digit_not_div3_down(N, M2), write('Макс. цифра не дел. на 3 для '), write(N), write(': up='), write(M1), write(', down='), write(M2), write(', ожидалось='), write(Expected), ((M1 =:= Expected, M2 =:= Expected) -> write(' ✓') ; write(' ✗')), nl. test_max_digit_not_div3_equivalence([]). test_max_digit_not_div3_equivalence([N|Rest]) :- max_digit_not_div3_up(N, M1), max_digit_not_div3_down(N, M2), (M1 =:= M2 -> write('✓ Макс. цифры не дел. на 3 для '), write(N), write(' эквивалентны') ; write('✗ Макс. цифры не дел. на 3 для '), write(N), write(' НЕ эквивалентны')), nl, test_max_digit_not_div3_equivalence(Rest). % =============================================== % ТЕСТЫ ДЛЯ КОЛИЧЕСТВА ДЕЛИТЕЛЕЙ % =============================================== test_divisor_count :- write('--- Тестирование количества делителей ---'), nl, % Тест известных значений TestCases = [ (1, 1), % делители: 1 (2, 2), % делители: 1, 2 (6, 4), % делители: 1, 2, 3, 6 (12, 6), % делители: 1, 2, 3, 4, 6, 12 (16, 5), % делители: 1, 2, 4, 8, 16 (24, 8), % делители: 1, 2, 3, 4, 6, 8, 12, 24 (100, 9), % делители: 1, 2, 4, 5, 10, 20, 25, 50, 100 (7, 2), % делители: 1, 7 (простое число) (13, 2) % делители: 1, 13 (простое число) ], forall(member((N, Expected), TestCases), test_divisor_count_case(N, Expected)), % Тест эквивалентности всех методов test_divisor_count_equivalence([1, 2, 6, 12, 16, 24, 36, 48]), nl. test_divisor_count_case(N, Expected) :- divisor_count_up(N, C1), divisor_count_down(N, C2), divisor_count_optimized(N, C3), write('Количество делителей '), write(N), write(': up='), write(C1), write(', down='), write(C2), write(', opt='), write(C3), write(', ожидалось='), write(Expected), ((C1 =:= Expected, C2 =:= Expected, C3 =:= Expected) -> write(' ✓') ; write(' ✗')), nl. test_divisor_count_equivalence([]). test_divisor_count_equivalence([N|Rest]) :- divisor_count_up(N, C1), divisor_count_down(N, C2), divisor_count_optimized(N, C3), ((C1 =:= C2, C2 =:= C3) -> write('✓ Количества делителей '), write(N), write(' эквивалентны') ; write('✗ Количества делителей '), write(N), write(' НЕ эквивалентны')), nl, test_divisor_count_equivalence(Rest). % =============================================== % ТЕСТЫ ЭКВИВАЛЕНТНОСТИ РЕКУРСИЙ % =============================================== test_recursion_equivalence :- write('--- Тестирование эквивалентности рекурсий ---'), nl, TestNumbers = [0, 1, 12, 123, 1234, 5555, 9876, 102030], write('Проверка эквивалентности для чисел: '), write(TestNumbers), nl, forall(member(N, TestNumbers), test_single_number_equivalence(N)), nl. test_single_number_equivalence(N) :- % Произведение цифр digit_product_up(N, P1), digit_product_down(N, P2), ProductOK = (P1 =:= P2), % Максимальная цифра не делящаяся на 3 max_digit_not_div3_up(N, M1), max_digit_not_div3_down(N, M2), MaxDigitOK = (M1 =:= M2), % Количество делителей (только для положительных) ( N > 0 -> divisor_count_up(N, C1), divisor_count_down(N, C2), divisor_count_optimized(N, C3), DivisorOK = (C1 =:= C2, C2 =:= C3) ; DivisorOK = true ), % Общий результат ( (ProductOK, MaxDigitOK, DivisorOK) -> write('✓ ') ; write('✗ ') ), write('Число '), write(N), write(' - все рекурсии эквивалентны'), nl. % =============================================== % ТЕСТЫ ГРАНИЧНЫХ СЛУЧАЕВ % =============================================== test_edge_cases :- write('--- Тестирование граничных случаев ---'), nl, % Тест с числом, содержащим только нули write('Тест с числом 1000:'), nl, digit_product_up(1000, P1000), write(' Произведение цифр 1000 = '), write(P1000), (P1000 =:= 0 -> write(' ✓') ; write(' ✗')), nl, % Тест с числом, все цифры которого делятся на 3 write('Тест с числом 3699 (все цифры дел. на 3):'), nl, max_digit_not_div3_up(3699, M3699), write(' Макс. цифра не дел. на 3 для 3699 = '), write(M3699), (M3699 =:= -1 -> write(' ✓') ; write(' ✗')), nl, % Тест с простыми числами write('Тест с простыми числами:'), nl, PrimeNumbers = [2, 3, 5, 7, 11, 13, 17, 19], forall(member(P, PrimeNumbers), test_prime_divisors(P)), % Тест с точными квадратами write('Тест с точными квадратами:'), nl, Squares = [1, 4, 9, 16, 25, 36, 49], forall(member(S, Squares), test_square_divisors(S)), nl. test_prime_divisors(P) :- divisor_count_optimized(P, Count), write(' Простое число '), write(P), write(' имеет '), write(Count), write(' делителей'), (Count =:= 2 -> write(' ✓') ; write(' ✗')), nl. test_square_divisors(S) :- divisor_count_optimized(S, Count), Sqrt is floor(sqrt(S)), ( Sqrt * Sqrt =:= S -> write(' Точный квадрат '), write(S), write(' имеет '), write(Count), write(' делителей ✓') ; write(' Ошибка: '), write(S), write(' не является точным квадратом ✗') ), nl. % =============================================== % ТЕСТЫ ПРОИЗВОДИТЕЛЬНОСТИ % =============================================== test_performance :- write('--- Тесты производительности ---'), nl, write('Сравнение производительности для больших чисел:'), nl, TestNumbers = [12345, 123456, 1234567], forall(member(N, TestNumbers), test_performance_single(N)), write('Сравнение оптимизированного алгоритма делителей:'), nl, LargeNumbers = [100, 1000, 10000], forall(member(N, LargeNumbers), test_divisor_performance(N)), nl. test_performance_single(N) :- write('Тестирование производительности для N = '), write(N), write(':'), nl, % Произведение цифр get_time(T1), digit_product_up(N, _), get_time(T2), digit_product_down(N, _), get_time(T3), TimeProductUp is T2 - T1, TimeProductDown is T3 - T2, write(' Произведение цифр: up='), write(TimeProductUp), write('с, down='), write(TimeProductDown), write('с'), nl, % Максимальная цифра get_time(T4), max_digit_not_div3_up(N, _), get_time(T5), max_digit_not_div3_down(N, _), get_time(T6), TimeMaxUp is T5 - T4, TimeMaxDown is T6 - T5, write(' Макс. цифра: up='), write(TimeMaxUp), write('с, down='), write(TimeMaxDown), write('с'), nl. test_divisor_performance(N) :- write('Тестирование делителей для N = '), write(N), write(':'), nl, get_time(T1), divisor_count_up(N, C1), get_time(T2), divisor_count_down(N, C2), get_time(T3), divisor_count_optimized(N, C3), get_time(T4), TimeUp is T2 - T1, TimeDown is T3 - T2, TimeOpt is T4 - T3, write(' Результаты: up='), write(C1), write(', down='), write(C2), write(', opt='), write(C3), nl, write(' Времена: up='), write(TimeUp), write('с, down='), write(TimeDown), write('с, opt='), write(TimeOpt), write('с'), nl, % Проверка ускорения оптимизированной версии ( TimeOpt < TimeUp -> SpeedUp is TimeUp / TimeOpt, write(' Ускорение оптимизированной версии: '), write(SpeedUp), write('x ✓') ; write(' Оптимизированная версия медленнее ✗') ), nl. % =============================================== % СТРЕСС-ТЕСТЫ % =============================================== stress_test :- write('--- Стресс-тесты ---'), nl, write('Тестирование 50 случайных чисел:'), nl, stress_test_random_numbers(50), write('Тестирование больших чисел:'), nl, LargeNumbers = [99999, 123456789, 987654321], forall(member(N, LargeNumbers), stress_test_large_number(N)), nl. stress_test_random_numbers(0) :- !. stress_test_random_numbers(N) :- N > 0, random(0, 10000, TestNumber), % Быстрая проверка корректности ( TestNumber > 0 -> divisor_count_up(TestNumber, C1), divisor_count_optimized(TestNumber, C2), (C1 =:= C2 -> Status = 'OK' ; Status = 'ERROR') ; Status = 'SKIP' ), (N mod 10 =:= 0 -> (write('Тест '), write(N), write(': '), write(TestNumber), write(' - '), write(Status), nl) ; true), N1 is N - 1, stress_test_random_numbers(N1). stress_test_large_number(N) :- write('Тестирование большого числа '), write(N), write(':'), nl, get_time(T1), digit_product_down(N, Product), get_time(T2), max_digit_not_div3_down(N, MaxDigit), get_time(T3), TimeProduct is T2 - T1, TimeMaxDigit is T3 - T2, write(' Произведение цифр: '), write(Product), write(' (время: '), write(TimeProduct), write('с)'), nl, write(' Макс. цифра не дел. на 3: '), write(MaxDigit), write(' (время: '), write(TimeMaxDigit), write('с)'), nl. % =============================================== % ДОПОЛНИТЕЛЬНЫЕ ТЕСТЫ % =============================================== % Тест специальных случаев для произведения цифр test_digit_product_special :- write('--- Специальные тесты произведения цифр ---'), nl, % Числа с нулями ZeroNumbers = [10, 102, 1020, 10203], forall(member(N, ZeroNumbers), test_zero_product(N)), % Числа из одинаковых цифр SameDigitNumbers = [111, 222, 3333, 55555], forall(member(N, SameDigitNumbers), test_same_digit_product(N)), nl. test_zero_product(N) :- digit_product_up(N, Product), write('Произведение цифр '), write(N), write(' = '), write(Product), (Product =:= 0 -> write(' ✓') ; write(' ✗')), nl. test_same_digit_product(N) :- digit_product_up(N, Product), % Получаем первую цифру FirstDigit is N mod 10, % Подсчитываем количество цифр atom_chars(N, Chars), length(Chars, DigitCount), % Ожидаемое произведение Expected is FirstDigit ^ DigitCount, write('Произведение цифр '), write(N), write(' = '), write(Product), write(', ожидалось '), write(Expected), (Product =:= Expected -> write(' ✓') ; write(' ✗')), nl.