În [1] am produs fișierul 3467.txt
, conținând lista Prolog a celor 320 de expresii aritmetice cu operanzii (în această ordine) 3, 4, 6 și 7, listă în care am căutat apoi pe cele care au o anumită valoare — astfel, aflasem acolo una singură cu valoarea 23
…
De fapt, sunt două astfel de expresii; ne-a scăpat una, fiindcă ne-am bazat pe operatorul "is
": am instanțiat S=23
și am evaluat fiecare termen H
din lista expresiilor prin H is S
(v. [1]). Dar S
fiind "integer", S is H
va produce tot "integer"; dacă instanțiam S=23.0
("float"), atunci S is H
producea (tot) "float" și rezulta o expresie cu valoarea 23.0
(care diferă de 23
…; în alte limbaje, am avea "conversii implicite").
În loc de "is
" trebuia să folosim "=:=
" (operatorul de "egalitate aritmetică"); acesta nu impune "același tip" pentru cele două argumente ale sale, încât rezultă (cum voiam) expresiile de valoare 23, împreună cu cele de valoare echivalentă 23.0:
?- see('3467.txt'), read(L), member(H, L), H =:= 23. L = [3+(4+(6+7)), 3-(4+(6+7)), 3*(4+(6+7)), 3/(4+(6+7)), 3+(4-(6+7)), 3-(4-(6+7)), 3*(4-(... + ...)), 3/(... - ...), ... + ...|...], H = 3*(4/6+7) ; % cu valoarea 23.0 (float) L = [3+(4+(6+7)), 3-(4+(6+7)), 3*(4+(6+7)), 3/(4+(6+7)), 3+(4-(6+7)), 3-(4-(6+7)), 3*(4-(... + ...)), 3/(... - ...), ... + ...|...], H = 3*(4+6)-7 ; % cu valoarea 23 (integer) false.
(tastând ';' după rezultatul curent afișat, Prolog va căuta următoarea soluție, plecând din punctul în care o aflase pe cea precedentă și afișează "false" dacă nu mai găsește una)
Iar cu S=24
rezultă direct "false", adică niciuna dintre cele 320 de expresii nu are ca valoare nici 24
, nici 24.0
. Subliniem ca și în [1], că este vorba numai de cele 320 de expresii cu operanzii 3,4,6,7 în această ordine…
Ca să obținem toate expresiile de valoare dată (vizând numai pe acestea, spre deosebire de [1]), putem folosi permutation/2
și arth_tree/2
(definit în [1]).
De exemplu, permutation([1,2,3], [A, B, C])
instanțiază variabilele A
, B
, C
cu câte unul dintre numerele indicate, astfel încât rezultă câte o permutare de [1,2,3]
; apoi, arth_tree([A,B,C], Expr)
va forma expresiile aritmetice cu operanzii dați de instanțierea curentă pentru [A,B,C]
și rămâne să reținem expresia curentă în cazul în care valoarea acesteia este cea dorită (în Prolog, termenii se deosebesc ca "tip" la nivel sintactic: numai variabilele încep cu majusculă, sau cu '_
').
Astfel, pentru operanzii 3,4,6,7 și valoarea 23 avem această formulare (și execuție):
?- permutation([3, 4, 6, 7], [_a, _b, _c, _d]), arth_tree([_a, _b, _c, _d], Expr), Val is Expr, Val =:= 23. % sau =:= 100, sau =:= 24.5 de exemplu _a = 3, _b = 4, _c = 6, _d = 7, Expr = 3*(4/6+7), Val = 23.0 ; _a = 3, _b = 4, _c = 6, _d = 7, Expr = 3*(4+6)-7, Val = 23 ; /* ... */ _a = 4, _b = 6, _c = 7, _d = 3, Expr = (4/6+7)*3, Val = 23.0 ; ERROR: Arithmetic: evaluation error: 'zero_divisor'
Pânâ la urmă, execuția a fost stopată… Iată un exemplu care evidențiază separat, eroarea de "împărțire la zero" (în contextul de execuție curent):
?- V is 6/(3+(4-7)). % 6 / 0 ERROR: Arithmetic: evaluation error: 'zero_divisor'
Predicatele current_prolog_flag/2
și set_prolog_flag/2
permit examinarea și modificarea contextului de execuție (reprezentat printr-un set de "flag"-uri); pentru float_zero_div
, setăm "infinity" în loc de "error":
?- current_prolog_flag(float_zero_div, X). X = error. % setarea curentă a determinat stoparea execuției ?- set_prolog_flag(float_zero_div, infinity). ?- V is 6/(3+(4-7)). V = 1.0Inf. % execuția nu va mai fi stopată
Reluând în noul context, obținem acum toate expresiile respective:
?- permutation([3,4,6,7], [_a,_b,_c,_d]), arth_tree([_a,_b,_c,_d], Expr), Val is Expr, Val =:= 23, write(Expr), tab(4), fail. 3*(4/6+7) 3*(4+6)-7 3*(6+4)-7 3*(7+4/6) 3*7-(4-6) 3*7-4+6 3*7+(6-4) 3*7+6-4 (4+6)*3-7 (4/6+7)*3 6+(3*7-4) 6+3*7-4 6-(4-3*7) 6-4+3*7 (6+4)*3-7 6-(4-7*3) 6-4+7*3 6+(7*3-4) 6+7*3-4 7*3-(4-6) 7*3-4+6 7*3+(6-4) 7*3+6-4 (7+4/6)*3 false.
În total, avem (aici, așezate matriceal) 24 de expresii aritmetice de valoare 23
(sau 23.0
, pentru 4 dintre acestea), cu operanzii (în diverse ordini) 3,4,6,7.
Repetând cu Val =:= 24
, rezultă zero expresii; la fel, pentru Val =:= 101
, sau 103..107; pentru Val =:= 26
găsim 4 expresii, iar cu Val =:= 24.5
sunt doar două expresii (dar pentru investigarea statistică a valorilor expresiilor se cuvine să folosim R, nu Prolog).
Subliniem că reluând execuția cu Val =:= 1.0Inf
, rezultă 12 expresii, toate de forma "6/0
" (unde zero provine scăzând 3+4
din 7, în diverse ordini).
Desigur, putem viza la fel și expresiile cu 5 sau mai mulți operanzi. De exemplu pentru operanzii 3,4,6,7 și 9, rezultă ca mai sus că există câte un număr de expresii având ca valori 24, sau 600, sau 450 (astfel, 9*(7+4/3)*6
are valoarea 450.0
); dar nu există, pentru valori ca 601, sau 444 (sau 445, etc.) — cu precizarea că în acest caz, a trebuit să modificăm în prealabil și starea flag-ului "float_overflow".
vezi Cărţile mele (de programare)