0

我觉得结果很奇怪。为什么不是0.3?有人能告诉我为什么会有这个结果吗?有没有可能解决这个问题。

 ?- X is 5.3-5.
    X = 0.2999999999999998.

    ?- 

我的第二个问题是如何将“小时”符号“13.45”---->“15.30”转换为小时数?例如,上面计算的 15.30-13.45 期间将是 1.85。但我需要在部分时间而不是剩余的数字上进行操作。像 15 1/2 - 13 /4,这种方式更好。我试试

?- X is (5.3-5)*100/60.
X = 0.4999999999999997.

?- X is (5.3-5)*100//60.
ERROR: ///2: Type error: `integer' expected, found `29.999999999999982'

有什么建议么?

4

3 回答 3

4

您从 SWI 得到的答案是正确的。
在许多编程语言中,几乎所有 Prolog 系统中,浮点实现都是基于二进制(radix = 2)系统。这个数字5.3不能在这个系统中精确表示,所以选择了一些近似值。减法特别适合暴露这种不准确性。

?- X is 5.3-5-0.3.
X = -1.6653345369377348e-16.

只要您使用 2 的幂和的数字(包括 2 -1、 2 -2 ......),只要后面的浮点数的精度允许,您就会得到精确的结果:

?- X is 5.000244140625-5-0.000244140625.
X = 0.0.

符合 ISO 标准的 Prolog 系统必须做的是确保在使用 write-option 写入浮点数时quoted(true),浮点数的写入方式可以精确地读回。

至于你的第二个问题:(//)/2仅在整数上定义。如果要将浮点数转换为整数,则在 ISO Prolog 中有常用的 LIA-1 函数:

floor/1, truncate/1, round/1, ceiling/1.

?- X is round(5.3).
X = 5.

但是,我宁愿推荐使用(div)/2代替(//)/2. (//)/2LIA-1:2012(标准 ISO/IEC 10967-1:2012)不再支持的含义— 有充分的理由。有关详细信息,请参阅此答案

于 2014-02-25T17:15:27.757 回答
2

关于这条线:

X is (5.3-5)*100//60.

谓词特别//是整数除法,您在浮点数上进行操作。您可以这样做:

X is round((5.3-5)*100/60).

或者

X is round((5.3-5)*100)//60.

当然,在这两种情况下,你都会得到,0因为它是关于0.3你是否在做浮动。所以不清楚这是否是你真正想要的。

其他有趣的选择:

?- X is (5.3-5)*100/ 60.
X = 0.4999999999999997.

?- X is float(round((5.3-5)*100) rdiv 60).
X = 0.5.
于 2014-02-25T16:59:29.540 回答
2

这是由于浮点运算,它(几乎*)总是不完美的。计算机以二进制工作,但人们大多以 10 为基数工作。这会在这里和那里引入一些不精确性;不精确性的严重程度取决于相关硬件和(有时)软件的工作方式。但关键是你无法准确预测错误会是什么,只能预测会有错误。

结果是你不能指望5.3-5完全0.3;您需要测试它是否真的很接近(例如在 0.00000000000001 内)。当您获得第二个示例中的结果时,您需要在使用结果之前显式转换为整数。您可以在此答案中阅读更多内容

[脚注:] 根据下面的评论,我将使用恰好是 2 的幂(即 2^i)或 2 的幂和(例如 7=4+2+1)的浮点数添加该算术可以用电脑精确计算。关于这是否实际上是“浮点运算”存在哲学争论。但它解释了为什么,例如,大多数语言会报告2.0 + 1.0is 3,但0.2 + 0.1类似于0.30000000000000004.

于 2014-02-25T16:47:56.693 回答