I wanted to play around with modular arithmetic and programmed some innocently looking function... but got totally surprised by the following unexpected behaviour:
crt <- function(x, mods = c(5, 7)) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
crt(20)
## [,1]
## [1,] 0
## [2,] 6
crt(55)
## [,1]
## [1,] 0
## [2,] 6
crt(1:100)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5 6 0
## [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 1 2 3 4 5 6 0 1 2 3 4 5
## [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 6 0 1 2 3 4 5 6 0 1 2 3
## [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
## [1,] 4 0 1 2 3 4 0 1 2 3 4 0
## [2,] 4 5 6 0 1 2 3 4 5 6 0 1
## [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61] [,62]
## [1,] 1 2 3 4 0 1 2 3 4 0 1 2
## [2,] 2 3 4 5 6 0 1 2 3 4 5 6
## [,63] [,64] [,65] [,66] [,67] [,68] [,69] [,70] [,71] [,72] [,73] [,74]
## [1,] 3 4 0 1 2 3 4 0 1 2 3 4
## [2,] 0 1 2 3 4 5 6 0 1 2 3 4
## [,75] [,76] [,77] [,78] [,79] [,80] [,81] [,82] [,83] [,84] [,85] [,86]
## [1,] 0 1 2 3 4 0 1 2 3 4 0 1
## [2,] 5 6 0 1 2 3 4 5 6 0 1 2
## [,87] [,88] [,89] [,90] [,91] [,92] [,93] [,94] [,95] [,96] [,97] [,98]
## [1,] 2 3 4 0 1 2 3 4 0 1 2 3
## [2,] 3 4 5 6 0 1 2 3 4 5 6 0
## [,99] [,100]
## [1,] 4 0
## [2,] 1 2
crt(x = 1:100, mods = c(12, 60))
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1
## [26] 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1 50
## [51] 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3
## [76] 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40
Why is the last function call crt(x = 1:100, mods = c(12, 60)) giving a totally different output? The first vectorized output crt(1:100) is what I wanted and expected, the last one doesn't seem structurally different but the result is... why? And how do I fix this to get the same output as the first?
According to ?Vectorize
The arguments named in the vectorize.args argument to Vectorize are the arguments passed in the ... list to mapply. Only those that are actually passed will be vectorized; default values will not.
Here, in the OP's function, there is default value for 'mods'. If we remove it
crt <- function(x, mods) {
sapply(mods, \(y) x %% y)
}
crt <- Vectorize(crt)
-testing
> crt(1:100, mods = c(5, 7))
[1] 1 2 3 4 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2 1 4 3 6 0 1 2 3 4 5 1 0 3 2 0 4 2 6 4 1 1 3 3 5 0 0 2 2 4 4 1 6 3 1 0 3 2 5 4 0 1 2 3 4
[75] 0 6 2 1 4 3 1 5 3 0 0 2 2 4 4 6 1 1 3 3 0 5 2 0 4 2
> crt(1:100, mods = c(12, 60))
[1] 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38 3 40 5 42 7 44 9 46 11 48 1
[50] 50 3 52 5 54 7 56 9 58 11 0 1 2 3 4 5 6 7 8 9 10 11 12 1 14 3 16 5 18 7 20 9 22 11 24 1 26 3 28 5 30 7 32 9 34 11 36 1 38
[99] 3 40
The output format is determined at two levels here - 1) sapply which by default uses simplify = TRUE and Vectorize which also by default have SIMPLIFY = TRUE
Also, based on the function defined, Vectorize is not really needed as internally, it does the looping with *apply functions and we already have the crt defined with sapply which loop over the 'mods'. The function applied %% on those parameters is %% which is already a vectorized function by default.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With