2014-02-25 101 views
-1

我发现结果很奇怪。为什么不是0.3?有人可以告诉我为什么会有这种结果吗?有没有可能解决这个问题。swi-prolog的奇怪算术

?- 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' 

有什么建议吗?

+2

最近在SWI-Prolog邮件列表中发现了一些非常类似的东西(https://lists.iai.uni-bonn.de/pipermail/swi-prolog/2014/012496.html),其中问题转向因为Pascal正在使用大量的编译器魔术来掩盖浮点数的复杂性,当Prolog不以相同的方式工作时会造成混淆。 “总是不完美”的 –

回答

1

这是由于浮点运算,这是(几乎*)总是不完善的。计算机以二进制形式工作,但大多数人工作在10位以下。这引起了一些不准确的地方;不精确度有多糟糕取决于问题硬件和(有时)软件的工作方式。但关键是你不能准确预测错误将会发生什么,只会有错误。

结果是,您不能指望5.3-5正好是0.3;您需要测试是否真的关闭(如0.00000000000001之内)。当你在第二个例子中得到结果时,你需要在使用结果之前显式地转换为整数。 You can read more in this answer。根据下面的注释,我将使用碰巧是2的幂(即2^i)或2的幂的和的浮点数(例如,7 = 4 + 4)来添加算术运算。 2 + 1)可以由计算机精确计算。关于这是否实际上是“浮点算术”,有一个哲学的论点。但它解释了为什么,例如,大多数语言将报告2.0 + 1.03,但0.2 + 0.1是类似于0.30000000000000004

+1

是不正确的。它适用于在一定范围内基于基数2的数字。 – false

+0

使用基于基数2的数字的算术不是浮点算术。这些是不同的概念。虽然计算机可能在某些情况下即使对于浮点运算也能产生正确的结果,但这并不意味着计算中不存在不精确性;这意味着不精确度太小而无法进入分配给计算结果的内存空间。 –

+1

@EdCottell:有些数字完全代表*,对于这些数字没有任何不准确的地方。如果你想知道细节,请咨询LIA-1。 – false

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. 
+0

谢谢,我不知道'圆'。非常简洁,乐于助人。 – vincent

+0

@vincent您可能想要浏览SWI Prolog的算术函数:http://www.swi-prolog.org/pldoc/man?section=functions – lurker

3

你从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符合做是为了确保编写带有写选项quoted(true)一个浮动时,浮动写这样的方式Prolog的系统,它可以准确读回。

至于你的第二个问题:(//)/2仅限于整数。如果你想将一个浮点数转换为你在ISO Prolog中通常使用的LIA-1函数的整数:

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

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

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