在Prolog中将浮点数转换为整数

7
如何在Prolog中将浮点数转换为整数?
我尝试了以下方法:
?- integer(truncate(sqrt(9))).
false.

?- integer(round(sqrt(9))).
false.

你的意思是什么?- X 是 round(sqrt(9)),integer(X)。你不能直接调用 integer/1,integer/1 的参数不会被求值。 - user502187
2个回答

16

您使用的谓词integer/1 当且仅当其参数为整数时为真。由于术语truncate(sqrt(9))不是整数,因此该谓词不成立,因此对于这个术语它失败了

有至少两种方法可以实现您想要的功能:

解决方案1:快速但不可靠

您可以使用谓词(is)/2在不同数字表示之间进行转换。特别是,请查看算术函数round, truncateceiling。例如:

?- X is round(sqrt(9)).
X = 3.

然而,请注意,使用浮点数总是高度问题复杂。例如:

?- X is sqrt(2^10000).
错误: is/2: Arithmetic: evaluation error: `float_overflow'

还存在其他问题,例如舍入误差和可能的下溢。

解决方案2:快速且通用

由于浮点数固有的缺陷,我强烈建议您使用更通用的机制。例如,几个Prolog系统支持有理数和具有无界精度的整数,而浮点数总是限于机器精度。

如果您需要整数平方根,请使用有限域约束。 使用约束,只需说明对于表示正平方根的整数X,什么是成立的:

?- X*X #= 9, X #>= 0.
X = 3.

这也适用于更大的整数:

?- X*X #= 2^10000, X #>= 0.
X = 1412467032...(省略了1496个数字)

更多信息请参阅


你还应该谈论一下浮点数的好处。它们不需要太多的空间。如果你想的话,你也可以使用自适应浮点数,这种浮点数会根据手头的问题自适应其精度。不确定是否有一些CLP(R)已经可以做到这一点了。 - user502187

-1
许多Prolog系统提供了一个额外的可求值函数integer/1,与可求值函数truncate/1相比,当后者像FPU指令一样实现时,它返回整数而不是浮点数。
FPU语义在一些Prolog系统中可用,如ECLiPSe Prolog和Jekejeke Prolog。对于大数,这种不同的行为是显而易见的:
/* with float semantics */
?- X is truncate(3.0E100).
X = 3.0E100

/* with integer semantics */
?- X is integer(3.0e100).
X = 299999999999999985344178410670684
7048562051886831693752693714362110399
5064698733443536124752361947136

这个函数 integer/1 在ISO核心标准中找不到。我正在测试:

?- X is integer(3.1415).
X = 3

我可以找到以下的支持:

System          Available
GNU Prolog      No
Ciao Prolog     Yes
YAP Prolog      Yes
SICStus Prolog  Yes
ECLiPSe Prolog  Yes (1)
SWI-Prolog      Yes (2)
Jekejeke Prolog Yes

(1) 如果参数不是整数,则ECLiPSe Prolog会抛出错误。因此需要与 truncate/1 等组合使用。
另一种选择是使用 fix/1,尽管有声称 fix/1 已被弃用。
(2) SWI-Prolog 不执行截断操作,而是进行四舍五入。
有声称整数/1 本身已被弃用。

在ISO Prolog中,这个功能由truncate/1提供。请参见9.1.6的truncateF→I。 - false
关于当前大数GMP的事实标准,如果您喜欢不必要地用零填充内存字节,您可能想使用大浮点数的整数语义。 - user502187

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接