将NA和评估为NaN的表达式相加,根据顺序会返回不同的结果,违反了交换律?

11

我正在调查R中数字运算的边角案例。我遇到了以下特殊情况,涉及零除以零:

(0/0)+NA
#> [1] NaN
NA+(0/0)
#> [1] NA

本文档由reprex软件包(v2.0.0)于2021-07-10创建

sessionInfo()
#> R version 4.1.0 (2021-05-18)
#> Platform: x86_64-apple-darwin17.0 (64-bit)
#> Running under: macOS Big Sur 10.16
#> 
#> Matrix products: default
#> BLAS:   /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRblas.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
#> 
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> loaded via a namespace (and not attached):
#>  [1] digest_0.6.27     withr_2.4.2       magrittr_2.0.1    reprex_2.0.0     
#>  [5] evaluate_0.14     highr_0.9         stringi_1.6.2     rlang_0.4.11     
#>  [9] cli_3.0.0         rstudioapi_0.13   fs_1.5.0          rmarkdown_2.9    
#> [13] tools_4.1.0       stringr_1.4.0     glue_1.4.2        xfun_0.23        
#> [17] yaml_2.2.1        compiler_4.1.0    htmltools_0.5.1.1 knitr_1.33

这显然违反了加法的交换律。我有两个问题:

  1. 是否有基于R语言定义的此行为的解释?

  2. 除了在加数子表达式中涉及副作用的情况外,是否存在其他违反加法交换律的例子(包括其他语言)?


4
?NaN中更加明确地说明:"涉及NaN的计算结果将返回NaN或者可能是NA,但这两种情况都无法保证,可能取决于R平台(因为编译器可能会重新排序计算步骤)"。 - Henrik
2
相关的NaN混淆(看起来与平台有关):R语言NaN + NA行为 - Henrik
2个回答

12

注意到

0/0
#[1] NaN

在这个问题中,+ 的行为更一般的例子如下:

NA + NaN
#[1] NA
 
NaN + NA
#[1] NaN

这是在r-devel thread中,R核心团队成员Tomas Kalibera回答了以下问题(我加粗并提供链接)。
是的,如果在 R 级别解决这个问题会带来太大的性能开销,并且会显著复杂化代码。涉及 NA 和 NaN 的二进制运算的结果是依赖于硬件的(NaN 负载的传播) - 在某些硬件上,它实际上是我们想要的方式 - 返回 NA,但在某些硬件上,你得到 NaN 或者有时候是 NA 和 NaN。此外,有 C 编译器优化重新排列代码,如 ?NaN 中所述。还有一些外部数值库不区分 NA 和 NaN(NA 是一个 R 概念)。所以我很遗憾,这是无法解决的。Duncan 提到的免责声明在 ?NaN/?NA 中,我认为这是可以的 - 有这么多的数值函数可能会遇到这些问题,它们都无法被记录下来。事实上,一些函数将保留 NA,我们不会让 NA 不必要地变成 NaN,但是免责声明说不要依赖这一点。

1
另一个相关的R-help主题,仅供完整性:非交换加法:NA+NaN!= NaN+NA - Henrik

7
根据 NA,这可能是由于 0/0 导致的 NaN。使用 NA 进行数值计算通常会导致 NA,但如果涉及到 NaN,则可能会出现任一结果(这取决于 R 平台)。然而,这并不是保证的,未来的 CPU 和/或编译器可能会有所不同。动态二进制翻译也可能影响此行为(使用 valgrind 进行计算时,即使没有 NaN 参与,使用 NA 进行计算也可能导致 NaN)。

1
此外,这个R-Help帖子也非常相关。我记得还看到过其他的帖子,是在r-devel中。 - Rui Barradas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接