You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

393 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

% ===============================================
% ТЕСТЫ ДЛЯ 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.