Код ниже проверяет, является ли данный год високосным или нет.Арифметика формулируется с использованием декларативной целочисленной арифметики из библиотеки clpfd , чтобы запрос можно было выполнить в «обратном порядке» для генерации последовательности високосных лет.Есть два варианта кода, изменяющие тест на то, является ли год столетием или нет, но поведение каждого варианта отличается, и ни один из них не работает правильно.
Я хочу создать последовательность високосных летс 1990 по 2005 год. Для этого я ввожу запрос Year in 1990..2005,leap_year1(Year),indomain(Year).
(или leap_year2
для проверки второго варианта).
Код, который я написал (с использованием SWI-Prolog 8.0.2):
:- use_module(library(clpfd)).
leap_year1(Year) :-
Year #> 0,
Year mod 4 #= 0,
(
Year mod 100 #= 0 ->
Year mod 400 #= 0 % 2000 is a leap year, 1900 is not
;
true % Not a century
).
leap_year2(Year) :-
Year #> 0,
Year mod 4 #= 0,
(
Year mod 100 #\= 0 ->
true % Not a century
;
Year mod 400 #= 0 % 2000 is a leap year, 1900 is not
).
Результаты запросов (SWI-Prolog 8.0.2):
?- Year in 1990..2005,leap_year1(Year),indomain(Year).
Year = 2000.
?- Year in 1990..2005,leap_year2(Year),indomain(Year).
Year = 1992 ;
Year = 1996 ;
Year = 2004.
Как видите, ни один запрос правильно не генерирует полную последовательность скачкагоды (1992, 1996, 2000, 2004).
Кроме того, следующие запросы примерно в 1900 году также дают аномальные результаты (комментарии добавлены):
% Verify that 1900 is not a leap year
?- not(leap_year1(1900)), not(leap_year2(1900)).
true.
% Verify that 1892, 1896, 1904 are leap years
?- leap_year1(1892), leap_year1(1896), leap_year1(1904).
true.
?- leap_year2(1892), leap_year2(1896), leap_year2(1904).
true.
% No solutions found (!)
?- Year in 1890..1905,leap_year1(Year),indomain(Year).
false.
% Solutions found as expected (complete result)
?- Year in 1890..1905,leap_year2(Year),indomain(Year).
Year = 1892 ;
Year = 1896 ;
Year = 1904.
Есть ли объяснение этомуповедение?Как мне изменить leap_year()
, чтобы он генерировал полную последовательность?
Обновление: (больше?) Завершено, но не понимаю, почему (!)
Разделение чека на века улучшает полноту запроса:
leap_year_century_fix(Year) :-
Year mod 100 #\= 0.
leap_year_century_fix(Year) :-
Year mod 100 #= 0,
Year mod 400 #= 0. % 2000 is a leap year, 1900 is not
leap_year3(Year) :-
Year #> 0,
Year mod 4 #= 0,
leap_year_century_fix(Year).
Теперь:
?- Year in 1890..1905,leap_year3(Year),indomain(Year).
Year = 1892 ;
Year = 1896 ;
Year = 1904 ;
false.
?- Year in 1990..2015,leap_year3(Year),indomain(Year).
Year = 1992 ;
Year = 1996 ;
Year = 2004 ;
Year = 2008 ;
Year = 2012 ;
Year = 2000.