下面的代码检查给定年份是否为a年。该算术使用来自库clpfd的声明性整数算术公式化,以便可以“反向”运行查询以生成a年序列。该代码有两种变体,它们改变了对年份是否是一个世纪的测试,但是每种变体的行为都不同,而且都无法正常工作。
我想生成一个从1990年到2005年的leap年序列。为此,我输入查询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.
如您所见,这两个查询都无法正确生成leap年的完整序列(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.
答案 0 :(得分:3)
只需使用和和或表达它,然后对或使用 reification :
leap(Y) :-
Y #> 0,
Y mod 4 #= 0,
(Y mod 100 #\= 0) #\/ (Y mod 400 #= 0).