2

I have this line in the knowledge base:

height(Hipot,Y) :- Y is sin(pi/6)*Hipot.

which calculates one of the cathetus of a right triangle.

When asking Prolog for the value of Y, that is the cathetus, I get an inaccurate number:

?- height(1,Y).
Y = 0.49999999999999994.

But the real value is 1/2, so it should output 0.5. I guess that the inaccuracy is because of the use of pi, but I want to keep using it so how can I round Y to 0.5?

false
  • 10,264
  • 13
  • 101
  • 209
netotz
  • 193
  • 1
  • 4
  • 12
  • 1
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Daniel Lyons Oct 25 '18 at 19:07
  • @DanielLyons I know that floating point numbers are "broken" in programming, I just wanted to know how to fix that problem in Prolog. – netotz Oct 25 '18 at 21:39
  • 2
    I think you're missing the point, by your comment to @mat below, because you have no real control over how Prolog prints internal values. The same thing happens in Python and every other language. The only time you have control is when you specifically convert the float into a string for output (or pass it to some output routine that will format it.) – Daniel Lyons Oct 25 '18 at 21:44

3 Answers3

5

One straight-forward solution is to use format/2 to output the number with a given "precision". For example:

?- height(1,Y), format("~2f", [Y]).
0.50
Y = 0.49999999999999994.

Note that floats will consistently lead to such issues, and wherever possible, I recommend to use for example rational numbers instead.

mat
  • 40,498
  • 3
  • 51
  • 78
  • I had seen `format/2` but I am not using it because I do not want to output the value, because I am using it to calculate something else that must be output. Thanks! – netotz Oct 25 '18 at 21:32
4

I am trying to learn prolog as well. The built-in round function only goes to the nearest integer, so I defined a rule that extends it to round to a certain number of digits:

round(X,Y,D) :- Z is X * 10^D, round(Z, ZA), Y is ZA / 10^D

I'm not sure if it's idiomatic, but it seems to work:

?- round(5.5555, Y, 2).
Y = 5.56.
Neal Fultz
  • 9,282
  • 1
  • 39
  • 60
0

By using format/3 you can output to an argument:

format(atom(A), '~2f', [Y]), writeln(A).