添加 NA 和计算结果为 NaN 的表达式会根据顺序返回不同的结果,是否违反了交换性?

Pau*_*din 11 r commutativity

我正在研究 R 中数字运算的极端情况。我遇到了以下涉及零除以零的特殊情况:

(0/0)+NA
#> [1] NaN
NA+(0/0)
#> [1] NA
Run Code Online (Sandbox Code Playgroud)

reprex 包( v2.0.0 )于 2021 年 7 月 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
Run Code Online (Sandbox Code Playgroud)

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

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

  2. 是否有其他不涉及加数子表达式中副作用的违反加法交换属性的例子(包括在其他语言中)?

Rui*_*das 12

注意到

0/0
#[1] NaN
Run Code Online (Sandbox Code Playgroud)

+问题中的行为的更一般示例如下:

NA + NaN
#[1] NA
 
NaN + NA
#[1] NaN
Run Code Online (Sandbox Code Playgroud)

这是在r-devel 线程中,R 核心团队成员Tomas Kalibera 回答了以下问题(我的重点和链接)。

是的,在 R 级别修复此问题的性能开销太大,并且会使代码显着复杂化。涉及 NA 和 NaN 的二元运算的结果取决于硬件(NaN 有效载荷的传播)——在某些硬件上,它实际上按照我们希望的方式工作——返回 NA——但在某些硬件上你得到 NaN 或有时是 NA 有时是 NaN . 还有 C 编译器优化对代码重新排序,如 ?NaN 中所述。然后还有不区分 NA 和 NaN 的外部数值库(NA 是一个 R 概念)。所以恐怕这是无法修复的。邓肯提到免责声明是在?NaN/?NA 中,我认为这没问题——有太多的数值函数可能会遇到这些问题,以至于无法将它们全部记录下来。有些函数实际上会保留NA,我们不会让NA不必要地变成NaN,但免责声明说这是不依赖的。


akr*_*run 8

?NA,这可能是因为NaN源于0/0

使用 NA 的数值计算通常会导致 NA:一个可能的例外是 NaN 也涉及到,在这种情况下可能会导致(这可能取决于 R 平台)。但是,这并不能保证,未来的 CPU 和/或编译器的行为可能会有所不同。动态二进制转换也可能影响这种行为(使用 valgrind,即使不涉及 NaN,使用 NA 的计算也可能导致 NaN)。