I have following code:
:-use_module(library(clpfd)).
afn(A,B,C):-
C #= B*A.
It works all right with integers but not with decimal numbers:
43 ?- afn(20, 10, C).
C = 200.
44 ?- afn(20, -10, C).
C = -200.
45 ?- afn(20, -10.5, C).
ERROR: Domain error: `clpfd_expression' expected, found `-10.5'
46 ?-
How can I work with decimals also here? Thanks.
Edit: I find following works with decimals:
afn(A,B,C):-
C is B * A.
67 ?- afn(20.895, 40.5, C).
C = 846.2475.
Is 'is' a correct approach ?!
You have to distinguish
Functional (or "moded") arithmetic. This is the one you are familiar with from other programming languages: You know which of your arguments are input and which is output, and you simply compute the output from the inputs. That's what you get from is/2 (which is part of standard Prolog), and if that's all you want to do, stick with it.
?- A=3, B=1.5, C is B * A.
C = 4.5
?- A=3, C=4.5, C is B * A.
instantiation fault <<< input B not kown
Relational arithmetic. Here, you state an equation or inequation that must hold between the variables involved. There is no notion of input/output arguments. The system's job is instead to make sure that all the stated relations hold at the time a solution for the variables is presented.
There are many different ways to implement relational arithmetic, and many methods only work for subsets of the problem (e.g. only integers, or only linear expressions), therefore these features are typically provided in the form of libraries.
One available implementation of general relational arithmetic over the real numbers is ECLiPSe's library(ic) (see 2, 3), which represents real numbers as floating point intervals:
?- A=3, C=4.5, C $= B * A.
B = 1.5__1.5 <<< precise result
?- C $= B * A, C=1, A=10.
B = 0.099999999999999992__0.1 <<< imprecise but accurate result
There are 2 delayed goals.
?- ln(X) $>= sin(X).
X = X{0.36787944117144228 .. 1.0Inf} <<< partially solved
There are 3 delayed goals.
Having said that, using interval arithmetic and interpreting results correctly is not always straightforward, that's why the kind of workarounds suggested by @mat can be useful (when applicable).