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

What is going on with floating point precision here?

参考的这个问题是code-golf challenge.

的观察

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

代码被@Giuseppe 简化了一些,所以我会为 reader 写一些评论。

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}

这是浮点精度问题造成的吗?或者这是由代码中的函数引起的,例如不等式检查或.Primitive("any")?我不相信这是由 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 或任何逻辑 check/conversion 步骤的问题,而是与浮点矩阵数学有关。

2) @user202729 在原始线程中的评论说这个问题在 Jelly 中仍然存在,一种代码高尔夫语言使人们更加相信这可能是一个浮点问题。

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

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
}

不同的方法迭代不同的函数,都从种子值 m 开始。如果给定的不动点稳定并且种子在该不动点的吸引力盆地内,函数迭代只会收敛到给定的不动点。

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

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

极限矩阵是一个稳定的 fixed-point 假设(在 Code Gulf 问题中陈述)存在 well-defined 极限。由于函数定义取决于 m,不动点是 m.

的函数也就不足为奇了

另一方面,使用 m = m %*% m 的建议变化是通过迭代函数

获得的
g <- function(X) X %*% X

注意所有幂等矩阵都是这个函数的不动点,但显然它们不可能都是稳定的不动点。显然,原定函数中的极限矩阵并不是g的稳定不动点(虽然是不动点)

要真正解决这个问题,您需要深入研究函数迭代下的矩阵不动点理论,以显示 为什么 [=16= 情况下的不动点] 不稳定。