【问题标题】:Loss of accuracy in modulus warning despite correct results尽管结果正确,但模量警告的准确性损失
【发布时间】:2018-02-05 00:02:49
【问题描述】:

我通过平方函数编写了一个递归模幂运算,它可以正常工作但会触发警告:

msquare <- function(x,n) (x*x) %% n

mod.exp <- function(a,k,n){
  ifelse(k <= 2,
       a^k %% n,
       ifelse(k %% 2 == 0,
            msquare(mod.exp(a,k %/% 2,n),n),
            (a * msquare(mod.exp(a,k %/% 2,n),n)) %% n))
}

我使用ifelse 编写了它,所以我可以使用它在指数上进行矢量化:

powers <- mod.exp(2,1:348,349)

当我运行上面的代码时,它会触发许多警告,例如:

在 ifelse(k

但是当我查看输出时(并将其与 Python 的模幂函数 pow() 进行比较),它是 100% 正确的。计算本身不应该采用大于 2*348^2 = 242208 的数字的模数,这远低于这甚至应该成为问题的水平。

是什么导致了这些警告,我该如何避免它们?我知道我可以以非递归方式重写它,这可能会有所帮助,尽管这仍然会使警告的来源变得神秘。

编辑时有点奇怪,下面的代码在没有警告的情况下运行:

powers <- sapply(1:348, function(x) mod.exp(2,x,349))

不知何故,递归调用似乎对警告负责。

【问题讨论】:

  • 我认为 R 总是评估 ifelse 的两个分支中的表达式,这可能意味着对不起作用的数字进行计算,即使这些数字永远不会被返回。
  • @Marius 的观点可能会帮助您使用逻辑来弄清楚发生了什么。或者,作为更暴力的替代方法,您可以通过使用options(warn=2,error=recover) 在触发警告时转到调试器来跟踪错误的来源

标签: r


【解决方案1】:

正如评论所暗示的那样,由于ifelse 而发生这种情况。

有关说明,请参见以下内容:

2^60 %% 349
[1] 210

2^61 %% 349
[1] 71
Warning message:
probable complete loss of accuracy in modulus 

msquare <- function(x,n) {
  message("msquare ", length(x))
  (x*x) %% n
}

mod.exp <- function(a,k,n) {
  print(k)
  ifelse(k <= 2,
     a^k %% n,
     ifelse(k %% 2 == 0,
            msquare(mod.exp(a,k %/% 2,n),n),
            (a * msquare(mod.exp(a,k %/% 2,n),n)) %% n))
}

# let's print the warning as it happens, without delay
powers <- withCallingHandlers(
  mod.exp(2, 1:62, 349), 
  warning = function(w) {
    print(w)
    invokeRestart("muffleWarning")
  }
)

您将看到在分支操作中始终拥有完整的向量,并且警告实际上是在前面发出的,因为大型元素仍将被发送到 if-branch 以及(在我的代码摘录的顶部)。

【讨论】:

  • 谢谢。我不完全理解这一点,但我的结论是递归 + 矢量化 + ifelse 不能很好地混合。我幼稚的观点是,我的递归函数在1:348 范围内的每个指数上被隐式独立调用,但是如果递归调用涉及每个阶段的完整向量,那么所有这些函数调用的开销将超过任何预期的速度-由于 vetorization 而上升。
  • 一个有趣的问题是,是否有一种通过短路进行矢量化操作的好方法...
  • @BenBolker 至少可以写一个myIfElse(cond, yesFun, noFun),其行为类似于例如带有FUN 参数的lapply,即myIfElse 将初始化结果,调用传递评估的cond 的两个函数并将返回值分配回根据cond 的位置的结果中
猜你喜欢
  • 2017-11-23
  • 2022-01-11
  • 1970-01-01
  • 2020-11-03
  • 2022-01-14
  • 2021-04-07
  • 2020-08-08
  • 2018-09-03
  • 2021-01-24
相关资源
最近更新 更多