有人可以帮助我找到一种方法来获得Prolog中的反因子...
例如inverse_factorial(6,X)
===> X = 3
。
我一直在努力工作。
我目前有阶乘,但我必须让它变得可逆。请帮帮我。
答案 0 :(得分:5)
Prolog的谓词是关系,所以一旦你定义了阶乘,你也隐含地定义了逆。但是,常规算术在Prolog中是模式化的,也就是说,(is)/2
或(>)/2
中的整个表达式必须在运行时知道,如果不是,则会发生错误。限制克服了这个缺点:
:- use_module(library(clpfd)). n_factorial(0, 1). n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
此定义现在可以双向运作。
?- n_factorial(N,6). N = 3 ; false. ?- n_factorial(3,F). F = 6 ; false.
由于SICStus 4.3.4和SWI 7.1.25也终止了以下内容:
?- n_factorial(N,N).
N = 1
; N = 2
; false.
有关详情,请参阅the manual。
答案 1 :(得分:2)
作为参考,这是我能提出的声明性factorial
谓词的最佳实现。
两个要点与@ false的答案不同:
它使用累加器参数,递归调用增加了我们乘以阶乘的因子,而不是基本情况为0
的标准递归实现。当已知阶乘并且初始数字不是时,这使得谓词更快。
它广泛使用if_/3
和(=)/3
来自模块reif
,以便在可能的情况下摆脱不必要的选择点。如果我们有两对可用于(#>)/3
(===)/6
部分的情况,它还会使用(=)/3
和if -> then
的变体if_
}。
factorial/2
factorial(N, F) :-
factorial(N, 0, 1, F).
factorial(N, I, N0, F) :-
F #> 0,
N #>= 0,
I #>= 0,
I #=< N,
N0 #> 0,
N0 #=< F,
if_(I #> 2,
( F #> N,
if_(===(N, I, N0, F, T1),
if_(T1 = true,
N0 = F,
N = I
),
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
),
if_(N = I,
N0 = F,
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
).
(#>)/3
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(>, true).
greater_true(<, false).
greater_true(=, false).
(===)/6
===(X1, Y1, X2, Y2, T1, T) :-
( T1 == true -> =(X1, Y1, T)
; T1 == false -> =(X2, Y2, T)
; X1 == Y1 -> T1 = true, T = true
; X1 \= Y1 -> T1 = true, T = false
; X2 == Y2 -> T1 = false, T = true
; X2 \= Y2 -> T1 = false, T = false
; T1 = true, T = true, X1 = Y1
; T1 = true, T = false, dif(X1, Y1)
).
?- factorial(N, N).
N = 1 ;
N = 2 ;
false. % One could probably get rid of the choice point at the cost of readability
?- factorial(N, 1).
N = 0 ;
N = 1 ;
false. % Same
?- factorial(10, N).
N = 3628800. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)).
% 79,283 inferences, 0.031 CPU in 0.027 seconds (116% CPU, 2541106 Lips)
N = 100. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518284253697920827223758251185210916864000000000000000000000000)).
% 78,907 inferences, 0.031 CPU in 0.025 seconds (125% CPU, 2529054 Lips)
false.
?- F #> 10^100, factorial(N, F).
F = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000,
N = 70 ;
F = 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000,
N = 71 ;
F = 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000,
N = 72 ;
...
答案 2 :(得分:0)
一种简单的“低技术”方式:枚举整数直到
实际上,您可以在现有的阶乘实现,目标和找到的反向中添加2个参数。
答案 3 :(得分:-3)
只需实现factorial(X,XFact)然后交换参数
factorial(X, XFact) :- f(X, 1, 1, XFact).
f(N, N, F, F) :- !.
f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F).