Problem
All eight density/probability/quantile functions in R/skewnorm.R and R/skewlnorm.R guard the length check behind an NA check:
if (lengths >= 4) {
nas <- any(is.na(q), is.na(mean), is.na(sd), is.na(shape))
if (!nas) chk_compatible_lengths(q, mean, sd, shape)
}
If any argument contains an NA, chk_compatible_lengths() never runs. Incompatible lengths then flow through to mapply/sn::*, which recycle silently (with a base R warning) and produce output of the wrong length with NAs in the wrong positions.
The NA masking that follows compounds it — na_shape is length(shape) but is used to index a result of max(length(...)):
Reproduction
Adding an NA turns a hard error into silently wrong output:
pskewnorm(1:6, 0, 1, c(1, 2, 3, 4))
#> Error: ... objects must be all zero length or the same length with some of
#> length of 1 but not lengths 1, 4 and 6.
pskewnorm(1:6, 0, 1, c(NA, 1, 2, 3))
#> Warning: longer argument not a multiple of length of shorter
#> [1] NA 0.9550173 0.9973002 0.9999367 NA 1.0000000
Only element 1 should be NA; element 5 is a recycling artefact. dskewnorm behaves the same way:
dskewnorm(1:6, 0, 1, c(NA, 1, 2, 3))
#> Warning: number of rows of result is not a multiple of vector length (arg 2)
#> [1] NA 1.055253e-01 8.863697e-03 2.676605e-04 NA 1.215177e-08
Affected
dskewnorm, pskewnorm, qskewnorm, dskewlnorm, pskewlnorm, qskewlnorm (and rskewnorm/rskewlnorm, which use the same if (!nas) pattern around their own length check).
Suggestion
The length check is a statement about argument lengths and doesn't need to care whether the values are NA — chk_compatible_lengths() should be able to run unconditionally. If it was gated for a reason, the NA masks should at least be recycled to the result length first (e.g. rep_len(is.na(shape), n)), the way dskewlnorm already does for x via xr <- rep_len(x, length(log_lik)).
Problem
All eight density/probability/quantile functions in
R/skewnorm.RandR/skewlnorm.Rguard the length check behind an NA check:If any argument contains an NA,
chk_compatible_lengths()never runs. Incompatible lengths then flow through tomapply/sn::*, which recycle silently (with a base R warning) and produce output of the wrong length with NAs in the wrong positions.The NA masking that follows compounds it —
na_shapeislength(shape)but is used to index a result ofmax(length(...)):Reproduction
Adding an NA turns a hard error into silently wrong output:
Only element 1 should be NA; element 5 is a recycling artefact.
dskewnormbehaves the same way:Affected
dskewnorm,pskewnorm,qskewnorm,dskewlnorm,pskewlnorm,qskewlnorm(andrskewnorm/rskewlnorm, which use the sameif (!nas)pattern around their own length check).Suggestion
The length check is a statement about argument lengths and doesn't need to care whether the values are NA —
chk_compatible_lengths()should be able to run unconditionally. If it was gated for a reason, the NA masks should at least be recycled to the result length first (e.g.rep_len(is.na(shape), n)), the waydskewlnormalready does forxviaxr <- rep_len(x, length(log_lik)).