|
|
% ===============================================
|
|
|
% LAB9 TASK1 - ОСНОВНЫЕ ПРЕДИКАТЫ PROLOG
|
|
|
% Реализация математических и списочных предикатов
|
|
|
% ===============================================
|
|
|
|
|
|
% ===============================================
|
|
|
% 1. ПРЕДИКАТ MAX/4
|
|
|
% ===============================================
|
|
|
|
|
|
% max(+X, +Y, +U, -Z) - Z максимальное из чисел X, Y, U
|
|
|
max(X, Y, U, Z) :-
|
|
|
MaxXY is max(X, Y),
|
|
|
Z is max(MaxXY, U).
|
|
|
|
|
|
% ===============================================
|
|
|
% 2. ФАКТОРИАЛ (РЕКУРСИЯ ВВЕРХ И ВНИЗ)
|
|
|
% ===============================================
|
|
|
|
|
|
% fact_up(+N, -X) - факториал с помощью рекурсии вверх
|
|
|
fact_up(0, 1) :- !.
|
|
|
fact_up(N, X) :-
|
|
|
N > 0,
|
|
|
N1 is N - 1,
|
|
|
fact_up(N1, X1),
|
|
|
X is N * X1.
|
|
|
|
|
|
% fact_down(+N, -X) - факториал с помощью рекурсии вниз
|
|
|
fact_down(N, X) :-
|
|
|
fact_down_helper(N, 1, X).
|
|
|
|
|
|
fact_down_helper(0, Acc, Acc) :- !.
|
|
|
fact_down_helper(N, Acc, Result) :-
|
|
|
N > 0,
|
|
|
N1 is N - 1,
|
|
|
Acc1 is Acc * N,
|
|
|
fact_down_helper(N1, Acc1, Result).
|
|
|
|
|
|
% ===============================================
|
|
|
% 3. СУММА ЦИФР ЧИСЛА (РЕКУРСИЯ ВВЕРХ И ВНИЗ)
|
|
|
% ===============================================
|
|
|
|
|
|
% digit_sum_up(+N, -Sum) - сумма цифр числа с рекурсией вверх
|
|
|
digit_sum_up(0, 0) :- !.
|
|
|
digit_sum_up(N, Sum) :-
|
|
|
N > 0,
|
|
|
Digit is N mod 10,
|
|
|
N1 is N // 10,
|
|
|
digit_sum_up(N1, Sum1),
|
|
|
Sum is Digit + Sum1.
|
|
|
|
|
|
% digit_sum_down(+N, -Sum) - сумма цифр числа с рекурсией вниз
|
|
|
digit_sum_down(N, Sum) :-
|
|
|
digit_sum_down_helper(N, 0, Sum).
|
|
|
|
|
|
digit_sum_down_helper(0, Acc, Acc) :- !.
|
|
|
digit_sum_down_helper(N, Acc, Sum) :-
|
|
|
N > 0,
|
|
|
Digit is N mod 10,
|
|
|
N1 is N // 10,
|
|
|
Acc1 is Acc + Digit,
|
|
|
digit_sum_down_helper(N1, Acc1, Sum).
|
|
|
|
|
|
% ===============================================
|
|
|
% 4. ПРОВЕРКА НА СВОБОДНОСТЬ ОТ КВАДРАТОВ
|
|
|
% ===============================================
|
|
|
|
|
|
% square_free(+N) - проверяет, свободно ли число от квадратов
|
|
|
square_free(N) :-
|
|
|
N > 0,
|
|
|
square_free_helper(N, 2).
|
|
|
|
|
|
square_free_helper(1, _) :- !.
|
|
|
square_free_helper(N, Divisor) :-
|
|
|
Divisor * Divisor > N, !.
|
|
|
square_free_helper(N, Divisor) :-
|
|
|
Square is Divisor * Divisor,
|
|
|
Square =< N,
|
|
|
N mod Square =\= 0,
|
|
|
NextDivisor is Divisor + 1,
|
|
|
square_free_helper(N, NextDivisor).
|
|
|
|
|
|
% ===============================================
|
|
|
% 5. ВВОД И ВЫВОД СПИСКОВ
|
|
|
% ===============================================
|
|
|
|
|
|
% read_list(-List) - чтение списка с клавиатуры
|
|
|
read_list(List) :-
|
|
|
write('Введите элементы списка (завершите ввод атомом end):'), nl,
|
|
|
read_list_elements(List).
|
|
|
|
|
|
read_list_elements([]) :-
|
|
|
write('Введите элемент (или end для завершения): '),
|
|
|
read(end), !,
|
|
|
write('Ввод завершен.'), nl.
|
|
|
|
|
|
read_list_elements([H|T]) :-
|
|
|
write('Введите элемент (или end для завершения): '),
|
|
|
read(H),
|
|
|
H \= end, !,
|
|
|
read_list_elements(T).
|
|
|
|
|
|
% write_list(+List) - вывод списка на экран
|
|
|
write_list([]) :-
|
|
|
write('[]'), nl.
|
|
|
|
|
|
write_list(List) :-
|
|
|
List \= [],
|
|
|
write('['),
|
|
|
write_list_elements(List),
|
|
|
write(']'), nl.
|
|
|
|
|
|
write_list_elements([H]) :-
|
|
|
write(H), !.
|
|
|
|
|
|
write_list_elements([H|T]) :-
|
|
|
write(H),
|
|
|
write(', '),
|
|
|
write_list_elements(T).
|
|
|
|
|
|
% ===============================================
|
|
|
% 6. СУММА ЭЛЕМЕНТОВ СПИСКА (РЕКУРСИЯ ВНИЗ)
|
|
|
% ===============================================
|
|
|
|
|
|
% sum_list_down(+List, ?Sum) - сумма элементов списка (рекурсия вниз)
|
|
|
sum_list_down([], 0).
|
|
|
sum_list_down([H|T], Sum) :-
|
|
|
sum_list_down(T, TailSum),
|
|
|
Sum is H + TailSum.
|
|
|
|
|
|
% ===============================================
|
|
|
% 7. СУММА ЭЛЕМЕНТОВ СПИСКА (РЕКУРСИЯ ВВЕРХ)
|
|
|
% ===============================================
|
|
|
|
|
|
% sum_list_up(+List, ?Sum) - сумма элементов списка (рекурсия вверх)
|
|
|
sum_list_up(List, Sum) :-
|
|
|
sum_list_up_helper(List, 0, Sum).
|
|
|
|
|
|
sum_list_up_helper([], Acc, Acc).
|
|
|
sum_list_up_helper([H|T], Acc, Sum) :-
|
|
|
Acc1 is Acc + H,
|
|
|
sum_list_up_helper(T, Acc1, Sum).
|
|
|
|
|
|
% ===============================================
|
|
|
% 8. ПРОГРАММА РАБОТЫ СО СПИСКАМИ
|
|
|
% ===============================================
|
|
|
|
|
|
% list_sum_program - программа для работы со списками
|
|
|
list_sum_program :-
|
|
|
write('=== ПРОГРАММА ВЫЧИСЛЕНИЯ СУММЫ СПИСКА ==='), nl,
|
|
|
read_list(List),
|
|
|
write('Прочитанный список: '), write_list(List),
|
|
|
sum_list_down(List, Sum),
|
|
|
write('Сумма элементов списка: '), write(Sum), nl.
|
|
|
|
|
|
% ===============================================
|
|
|
% 9. УДАЛЕНИЕ ЭЛЕМЕНТОВ ПО СУММЕ ЦИФР
|
|
|
% ===============================================
|
|
|
|
|
|
% remove_by_digit_sum(+List, +TargetSum, -Result) - удаляет элементы с заданной суммой цифр
|
|
|
remove_by_digit_sum([], _, []).
|
|
|
remove_by_digit_sum([H|T], TargetSum, Result) :-
|
|
|
integer(H),
|
|
|
H >= 0,
|
|
|
digit_sum_up(H, DigitSum),
|
|
|
( DigitSum =:= TargetSum ->
|
|
|
remove_by_digit_sum(T, TargetSum, Result)
|
|
|
; Result = [H|TailResult],
|
|
|
remove_by_digit_sum(T, TargetSum, TailResult)
|
|
|
).
|
|
|
|
|
|
remove_by_digit_sum([H|T], TargetSum, [H|TailResult]) :-
|
|
|
(\+ integer(H) ; H < 0),
|
|
|
remove_by_digit_sum(T, TargetSum, TailResult).
|
|
|
|
|
|
% ===============================================
|
|
|
% ДЕМОНСТРАЦИОННЫЕ И ВСПОМОГАТЕЛЬНЫЕ ПРЕДИКАТЫ
|
|
|
% ===============================================
|
|
|
|
|
|
% task_info - информация о задании
|
|
|
task_info :-
|
|
|
write('РЕАЛИЗОВАННЫЕ ПРЕДИКАТЫ:'), nl,
|
|
|
write('1. max(X, Y, U, Z) - максимальное из трех чисел'), nl,
|
|
|
write('2. fact_up(N, X) - факториал (рекурсия вверх)'), nl,
|
|
|
write('3. fact_down(N, X) - факториал (рекурсия вниз)'), nl,
|
|
|
write('4. digit_sum_up(N, Sum) - сумма цифр (рекурсия вверх)'), nl,
|
|
|
write('5. digit_sum_down(N, Sum) - сумма цифр (рекурсия вниз)'), nl,
|
|
|
write('6. square_free(N) - проверка свободности от квадратов'), nl,
|
|
|
write('7. read_list(List) - чтение списка с клавиатуры'), nl,
|
|
|
write('8. write_list(List) - вывод списка на экран'), nl,
|
|
|
write('9. sum_list_down(List, Sum) - сумма списка (рекурсия вниз)'), nl,
|
|
|
write('10. sum_list_up(List, Sum) - сумма списка (рекурсия вверх)'), nl,
|
|
|
write('11. remove_by_digit_sum(List, TargetSum, Result) - удаление по сумме цифр'), nl,
|
|
|
write('12. list_sum_program - программа работы со списками'), nl.
|
|
|
|
|
|
% show_examples - показать примеры использования
|
|
|
show_examples :-
|
|
|
write('ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ:'), nl,
|
|
|
write('?- max(5, 3, 7, Z). % Z = 7'), nl,
|
|
|
write('?- fact_up(5, X). % X = 120'), nl,
|
|
|
write('?- fact_down(5, X). % X = 120'), nl,
|
|
|
write('?- digit_sum_up(123, Sum). % Sum = 6'), nl,
|
|
|
write('?- digit_sum_down(123, Sum). % Sum = 6'), nl,
|
|
|
write('?- square_free(12). % false (делится на 4)'), nl,
|
|
|
write('?- square_free(15). % true'), nl,
|
|
|
write('?- sum_list_down([1,2,3], S). % S = 6'), nl,
|
|
|
write('?- sum_list_up([1,2,3], S). % S = 6'), nl,
|
|
|
write('?- remove_by_digit_sum([12,21,34,43], 3, R). % R = [34,43]'), nl,
|
|
|
write('?- list_sum_program. % интерактивная программа'), nl.
|
|
|
|
|
|
% test_all_predicates - тестирование всех предикатов
|
|
|
test_all_predicates :-
|
|
|
write('=== ТЕСТИРОВАНИЕ ВСЕХ ПРЕДИКАТОВ ==='), nl,
|
|
|
|
|
|
% Тест max
|
|
|
write('Тест max: '),
|
|
|
max(5, 3, 7, Z1),
|
|
|
write('max(5,3,7) = '), write(Z1), nl,
|
|
|
|
|
|
% Тест факториалов
|
|
|
write('Тест факториалов: '),
|
|
|
fact_up(5, F1),
|
|
|
fact_down(5, F2),
|
|
|
write('fact_up(5) = '), write(F1), write(', fact_down(5) = '), write(F2), nl,
|
|
|
|
|
|
% Тест суммы цифр
|
|
|
write('Тест суммы цифр: '),
|
|
|
digit_sum_up(123, S1),
|
|
|
digit_sum_down(123, S2),
|
|
|
write('digit_sum_up(123) = '), write(S1), write(', digit_sum_down(123) = '), write(S2), nl,
|
|
|
|
|
|
% Тест square_free
|
|
|
write('Тест square_free: '),
|
|
|
(square_free(15) -> write('15 - свободно от квадратов') ; write('15 - не свободно от квадратов')), write(', '),
|
|
|
(square_free(12) -> write('12 - свободно от квадратов') ; write('12 - не свободно от квадратов')), nl,
|
|
|
|
|
|
% Тест сумм списков
|
|
|
write('Тест сумм списков: '),
|
|
|
sum_list_down([1,2,3,4], Sum1),
|
|
|
sum_list_up([1,2,3,4], Sum2),
|
|
|
write('sum_list_down([1,2,3,4]) = '), write(Sum1), write(', sum_list_up([1,2,3,4]) = '), write(Sum2), nl,
|
|
|
|
|
|
% Тест удаления по сумме цифр
|
|
|
write('Тест удаления по сумме цифр: '),
|
|
|
remove_by_digit_sum([12, 21, 34, 43, 105], 3, Filtered),
|
|
|
write('remove_by_digit_sum([12,21,34,43,105], 3) = '), write_list(Filtered),
|
|
|
|
|
|
write('=== ТЕСТИРОВАНИЕ ЗАВЕРШЕНО ==='), nl.
|
|
|
|
|
|
% compare_recursions(+N) - сравнение рекурсий для числа N
|
|
|
compare_recursions(N) :-
|
|
|
write('Сравнение рекурсий для числа '), write(N), write(':'), nl,
|
|
|
|
|
|
% Факториалы
|
|
|
fact_up(N, F1),
|
|
|
fact_down(N, F2),
|
|
|
write(' Факториал (вверх): '), write(F1), nl,
|
|
|
write(' Факториал (вниз): '), write(F2), nl,
|
|
|
write(' Факториалы равны: '), (F1 =:= F2 -> write('да') ; write('нет')), nl,
|
|
|
|
|
|
% Суммы цифр
|
|
|
digit_sum_up(N, S1),
|
|
|
digit_sum_down(N, S2),
|
|
|
write(' Сумма цифр (вверх): '), write(S1), nl,
|
|
|
write(' Сумма цифр (вниз): '), write(S2), nl,
|
|
|
write(' Суммы цифр равны: '), (S1 =:= S2 -> write('да') ; write('нет')), nl.
|
|
|
|
|
|
% interactive_demo - интерактивная демонстрация
|
|
|
interactive_demo :-
|
|
|
write('=== ИНТЕРАКТИВНАЯ ДЕМОНСТРАЦИЯ ==='), nl,
|
|
|
write('Выберите операцию:'), nl,
|
|
|
write('1. Тест max(X,Y,U,Z)'), nl,
|
|
|
write('2. Тест факториала'), nl,
|
|
|
write('3. Тест суммы цифр'), nl,
|
|
|
write('4. Тест свободности от квадратов'), nl,
|
|
|
write('5. Работа со списками'), nl,
|
|
|
write('6. Удаление по сумме цифр'), nl,
|
|
|
write('7. Выход'), nl,
|
|
|
write('Введите номер (1-7): '),
|
|
|
read(Choice),
|
|
|
handle_choice(Choice).
|
|
|
|
|
|
handle_choice(1) :-
|
|
|
write('Введите три числа X, Y, U: '),
|
|
|
read(X), read(Y), read(U),
|
|
|
max(X, Y, U, Z),
|
|
|
write('Максимальное из '), write(X), write(', '), write(Y), write(', '), write(U),
|
|
|
write(' = '), write(Z), nl,
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(2) :-
|
|
|
write('Введите число для вычисления факториала: '),
|
|
|
read(N),
|
|
|
( N >= 0 ->
|
|
|
fact_up(N, F1),
|
|
|
fact_down(N, F2),
|
|
|
write('Факториал '), write(N), write(' (рекурсия вверх) = '), write(F1), nl,
|
|
|
write('Факториал '), write(N), write(' (рекурсия вниз) = '), write(F2), nl
|
|
|
; write('Число должно быть неотрицательным!'), nl
|
|
|
),
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(3) :-
|
|
|
write('Введите число для вычисления суммы цифр: '),
|
|
|
read(N),
|
|
|
( N >= 0 ->
|
|
|
digit_sum_up(N, S1),
|
|
|
digit_sum_down(N, S2),
|
|
|
write('Сумма цифр '), write(N), write(' (рекурсия вверх) = '), write(S1), nl,
|
|
|
write('Сумма цифр '), write(N), write(' (рекурсия вниз) = '), write(S2), nl
|
|
|
; write('Число должно быть неотрицательным!'), nl
|
|
|
),
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(4) :-
|
|
|
write('Введите число для проверки свободности от квадратов: '),
|
|
|
read(N),
|
|
|
( N > 0 ->
|
|
|
( square_free(N) ->
|
|
|
write('Число '), write(N), write(' свободно от квадратов'), nl
|
|
|
; write('Число '), write(N), write(' НЕ свободно от квадратов'), nl
|
|
|
)
|
|
|
; write('Число должно быть положительным!'), nl
|
|
|
),
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(5) :-
|
|
|
list_sum_program,
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(6) :-
|
|
|
write('Введите список чисел [a,b,c,...]: '),
|
|
|
read(List),
|
|
|
write('Введите целевую сумму цифр: '),
|
|
|
read(TargetSum),
|
|
|
remove_by_digit_sum(List, TargetSum, Result),
|
|
|
write('Исходный список: '), write_list(List),
|
|
|
write('После удаления элементов с суммой цифр '), write(TargetSum), write(': '),
|
|
|
write_list(Result),
|
|
|
interactive_demo.
|
|
|
|
|
|
handle_choice(7) :-
|
|
|
write('До свидания!'), nl.
|
|
|
|
|
|
handle_choice(_) :-
|
|
|
write('Неверный выбор! Попробуйте снова.'), nl,
|
|
|
interactive_demo.
|
|
|
|
|
|
% benchmark_recursions(+N) - бенчмарк рекурсий
|
|
|
benchmark_recursions(N) :-
|
|
|
write('Бенчмарк рекурсий для N = '), write(N), write(':'), nl,
|
|
|
|
|
|
% Бенчмарк факториалов
|
|
|
get_time(T1),
|
|
|
fact_up(N, _),
|
|
|
get_time(T2),
|
|
|
fact_down(N, _),
|
|
|
get_time(T3),
|
|
|
|
|
|
TimeUp is T2 - T1,
|
|
|
TimeDown is T3 - T2,
|
|
|
|
|
|
write(' Факториал (рекурсия вверх): '), write(TimeUp), write(' сек'), nl,
|
|
|
write(' Факториал (рекурсия вниз): '), write(TimeDown), write(' сек'), nl,
|
|
|
|
|
|
% Бенчмарк сумм цифр
|
|
|
get_time(T4),
|
|
|
digit_sum_up(N, _),
|
|
|
get_time(T5),
|
|
|
digit_sum_down(N, _),
|
|
|
get_time(T6),
|
|
|
|
|
|
TimeSumUp is T5 - T4,
|
|
|
TimeSumDown is T6 - T5,
|
|
|
|
|
|
write(' Сумма цифр (рекурсия вверх): '), write(TimeSumUp), write(' сек'), nl,
|
|
|
write(' Сумма цифр (рекурсия вниз): '), write(TimeSumDown), write(' сек'), nl. |