我通过平方函数编写了一个递归模幂运算,该函数正常工作但会触发警告:
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))
不知何故,递归调用似乎对警告负责。
答案 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
(这给出了示例)在我的代码摘录的顶部)。