r - 这里的浮点精度是怎么回事?



这个问题是参考来自代码高尔夫挑战的观察。

提交的 R 解决方案是一个可行的解决方案,但我们中的一些人(也许只是我)似乎对为什么需要初始X=m重新分配感到目瞪口呆。

代码被@Giuseppe降低了一点,所以我会为读者写一些评论。

function(m){
X=m
# Re-assign input m as X
while(any(X-(X=X%*%m))) 0
# Instead of doing the meat of the calculation in the code block after `while`
# OP exploited its infinite looping properties to perform the
# calculations within the condition check.
# `-` here is an abuse of inequality check and relies on `any` to coerce
# the numeric to logical. See `as.logical(.Machine$double.xmin)`
# The code basically multiplies the matrix `X` with the starting matrix `m`            
# Until the condition is met: X == X%*%m
X
# Return result
}

据我所知。乘X%*%m等同于X%*%X,因为X只是m的迭代自乘版本。矩阵收敛后,将mX的其他副本相乘不会改变其值。将上述函数定义为v后,请参阅线性代数教科书或v(m)%*%v(m)%*%v(m)%*%v(m)%*%v(m)%*%m%*%m。好玩吧?

那么问题来了,为什么@CodesInChaos对这个想法的实现不起作用?

function(m){while(any(m!=(m=m%*%m)))0 m}

这是由浮点精度问题引起的吗?或者这是由代码中的 a 函数引起的,例如不等式检查或 .原始("任何")?我不认为这是由as.logical引起的,因为 R 似乎将小于.Machine$double.xmin的错误强制为 0。

这是上面的演示。我们只是循环并采取mm%*%m之间的差异。当我们尝试收敛随机矩阵时,此错误变为 0。它似乎收敛然后最终吹到 0/INF,具体取决于输入。

mat = matrix(c(7/10, 4/10, 3/10, 6/10), 2, 2, byrow = T)
m = mat
for (i in 1:25) {
m = m%*%m
cat("Mean Error:", mean(m-(m=m%*%m)), 
"n Float to Logical:", as.logical(m-(m=m%*%m)),
"n iter", i, "n")
}

关于为什么这是一个浮点数学问题的一些额外想法

1)循环表明这可能不是any或任何逻辑检查/转换步骤的问题,而是与浮点矩阵数学有关。

2) @user202729在原始线程中的评论是,这个问题在 Jelly 中仍然存在,这是一种代码高尔夫语言,这更证实了这可能是一个浮点问题的想法。

不同的方法迭代不同的函数,都从种子值m开始。函数迭代仅在给定的不动点稳定且种子在该不动点的吸引力范围内时收敛到该定点。

在原始代码中,您正在迭代函数

f <- function(X) X %*% m

极限矩阵是一个稳定的不动点,假设(在代码海湾问题中陈述)存在一个明确定义的极限。由于函数定义依赖于m,因此不动点是m的函数也就不足为奇了。

另一方面,使用m = m %*% m提出的变体是通过迭代函数获得

g <- function(X) X %*% X

请注意,所有幂等矩阵都是此函数的不动点,但显然它们不可能都是稳定的不动点。显然,原始固定函数中的极限矩阵不是g的稳定不动点(即使它是一个不动点)。

要真正确定这一点,您需要进入函数迭代下的矩阵不动点理论,以说明为什么g情况下的不动点是不稳定的。

这确实是一个浮点数学问题。要查看它,请参阅此函数的结果:

test2 <- function(m) {
c <- 0
res <- list()
while (any(m!=(m=m%*%m))) {
c <- c + 1
res[[c]] <- m
}
print(c)
res
}

若要在具有一定容差的情况下测试相等性,可以使用:

test3 <- function(m) {
while (!isTRUE(all.equal(m, m <- m %*% m))) 0
m
}

最新更新