0

I have to write a piece of prolog where I have to calculate which position in an array is used to store a value. However the result of these calculations should return an integer, so I use the floor/1 predicate to get myself the integer of the value but this doesn't work in my code. It keeps returning a number with decimal point, for example 3.0 instead of 3

The following is my code:

assign_value(El, NumberArray, RowNumber, I) :-
    ground(El),
    Number is NumberArray[El],
    Col is I/3,
    Row is RowNumber/3*3,
    Sum is floor(Col + Row + 1),
    subscript(Number, [Sum], El).
assign_value(_, _, _, _).

The result of the Sum is floor(Col + Row + 1) is never an integer and I don't know why. Can anyone help me with this?

false
  • 10,264
  • 13
  • 101
  • 209
Delko
  • 25
  • 4

3 Answers3

2

In ISO Prolog, the evaluable functor floor/1 has as signature (9.1.1 in ISO/IEC 13211-1):

floorF→I

So it expects a float and returns an integer.

However, I do not believe that first creating floats out of integers and then flooring them back to integers is what you want, instead, consider to use (div)/2 in place of (/)/2 thereby staying with integers all the time.

false
  • 10,264
  • 13
  • 101
  • 209
  • The OP's question was not about ISO-Prolog (@false added that tag). ECLiPSe (in native mode) has reasons to differ here, see the other answers. – jschimpf Apr 16 '14 at 01:36
  • 1
    @jschimpf: This is a case where ECLiPSE differs from ISO-Prolog in a not very obvious manner. For this reason both the tag and my statement is of relevance to the question. However, you seem to have overseen the last observation in my answer which is by far much more important to OP's question. – false Apr 16 '14 at 11:20
1

From the documentation of floor/2 (http://www.eclipseclp.org/doc/bips/kernel/arithmetic/floor-2.html)

The result type is the same as the argument type. To convert the type to integer, use integer/2.

For example:

...,
Floor is floor(Col+Row+1), Sum is integer(Floor).
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
hakank
  • 6,629
  • 1
  • 17
  • 27
  • Ah, I should read the documentation better. Thanks a lot, the integer() predicate worked. – Delko Apr 15 '14 at 17:22
  • @user2106957 Thanks. You should also read what Nicholas Carey writes about division etc... – hakank Apr 15 '14 at 17:24
1

Reading the documentation for floor/2, we see that

[floor/2] works on all numeric types. The result value is the largest integral value that is smaller that Number (rounding down towards minus infinity).

The result type is the same as the argument type. To convert the type to integer, use integer/2.

So you get the same type you supplied as the argument. Looking further at your predicate, we see the use of the / operator. Reading the documentation further, we see that

'/'/3 is used by the ECLiPSe compiler to expand evaluable arithmetic expressions. So the call to /(Number1, Number2, Result) is equivalent to

Result is Number1 / Number2

which should be preferred for portability.

The result type of the division depends on the value of the global flag prefer_rationals. When it is off, the result is a float, when it is on, the result is a rational.

Your division operation never returns an integer, meaning that things get upcast to floating point.

If you want to perform integer division, you should use the operators // or div.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • 1
    You should definitely not perform integer division with `//`. OP's example is clearly a case of "partitioning". See http://stackoverflow.com/questions/22020694/strange-arithmetic-with-swi-prolog/22021419#22021419 and references. – false Apr 16 '14 at 11:16