这个问题在参考是来自代码高尔夫挑战的观察。
提交的 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
。矩阵收敛后,将其他副本相乘m
或X
不改变其值。请参阅线性代数教科书或v(m)%*%v(m)%*%v(m)%*%v(m)%*%v(m)%*%m%*%m
将上述函数定义为v
。好玩吧?
那么问题来了,为什么@CodesInChaos 对这个想法的实现行不通呢?
function(m){while(any(m!=(m=m%*%m)))0 m}
这是由浮点精度问题引起的吗?或者这是由代码中的 a 函数引起的,例如不等式检查或 .Primitive("any")?我不相信这是as.logical
由于 R 似乎强制错误小于.Machine$double.xmin
0 造成的。
这是上面的演示。m
我们只是循环并获取和之间的差异m%*%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 在原始线程中的评论说这个问题在果冻中仍然存在,代码高尔夫语言更加相信这可能是一个浮点问题。