c = .1
e = .3
(200 - 100) / (200 - 100) * (e - c) + c == .3
输出:
[1] TRUE
但是:
(e - c) * (200 - 100) / (200 - 100) + c == .3
输出:
[1] FALSE
为什么重新排序会更改输出?
这个问题与运算的代数顺序无关,因为两个左手表达式在理论上都会给出相同的结果。
我怀疑可能是编译优化导致了结果的差异。
在第一个等式中,两个c都将抵消而没有实际在(e-c)部分中进行算术运算。
在第二个方程中,必须计算(e-c)内部的算术,因此计算机必须计算.3-.1,这会导致不精确的误差。
答案 0 :(得分:3)
在@AkselA的示例之后,为了简单起见,删除了+c
:
r1 <- a / b * (e - c)
r2 <- (e - c) * a / b
r3 <- (e - c) * (a / b)
options(digits=22)
r1
## [1] 0.1999999999999999833467
r2
## [1] 0.2000000000000000111022
r3
## [1] 0.1999999999999999833467
我们可以进一步简化为d <- e-c; a/b*d == d*a/b
并获得相同的结果。
结果取决于是否将b
除以(e-c)
(r1
,r3
)还是之后(r2
)。由于浮点算术是可交换的,但不具有关联性(请参见Wikipedia或this answer中的任何链接),我们可以看到r1
和{{ 1}}确实应该完全相同(对r3
和a/b
进行求和,然后相乘),不一定与e-c
相同({{1}乘以r2
,则e-c
除以a
)。
(e-c)*a
或b
表明str(a)
是浮点数,而不是整数;如果需要整数,请使用storage.mode(a)
答案 1 :(得分:1)
老实说,我不知道发生了什么。当然,浮点数是显而易见的,但是我看不出为什么重新排序这样的方程式会改变东西。我已经尝试过使用方程的稍微简化的版本,更改值并四处移动。
eq.1和eq.2与OP相同,由于操作员的偏好,eq.3等于eq.1(请参见?Syntax
)。 *
和/
先于+
和-
求值,除了它们从左至右求值,并且括号从内到外解析。因此,在等式1和等式3中,顺序为-
/
*
+
,在等式2中,顺序为-
*
/
+
。
a <- 100
b <- 100
c <- 0.1
e <- 0.3
r1 <- a / b * (e - c) + c # [1]
r2 <- (e - c) * a / b + c # [2]
r3 <- (e - c) * (a / b) + c # [3]
r1 == r2 # FALSE
r1 == r3 # TRUE
sprintf("%.20f", c(r1, r2, r3))
# "0.29999999999999998890" "0.30000000000000004441" "0.29999999999999998890"
很明显,确切的值取决于运算的顺序,尽管从纯粹的算术术语来看,这并不重要(它们是关联的)。但是只有在使用某些特定值时,顺序才有所不同。如果将a
和b
设置为10 say,或者将c
设置为0.2,则值是相同的。我的直觉是,这是由等式1中的整数模式除法和等式2中的浮点模式除法引起的,第二种引入了第一个没有舍入误差(取决于起始值)。当然,真正的带回家的信息是标记linked的作用,在比较浮点数时您需要格外小心,但是对这种精确的行为做出明确的解释仍然很不错。