尽管结果正确,但模数警告的准确度会下降

时间:2018-02-05 00:02:49

标签: r

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

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 <= 2,a ^ k %% n,ifelse(k %% 2 == 0,msquare(mod.exp(a,...:   模数准确度可能完全丧失

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

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

开启编辑奇怪的是,以下代码无需警告:

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

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

1 个答案:

答案 0 :(得分:2)

这是因为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(这给出了示例)在我的代码摘录的顶部)。