【问题标题】:Difference between NA_real_ and NaNNA_real_ 和 NaN 的区别
【发布时间】:2022-01-25 00:34:49
【问题描述】:

当我使用.Internal(inspect())NA_real_NaN 时,它会返回,

> .Internal(inspect(NA_real_))
@0x000001e79724d0e0 14 REALSXP g0c1 [REF(2)] (len=1, tl=0) nan
> .Internal(inspect(NaN))
@0x000001e797264a88 14 REALSXP g0c1 [REF(2)] (len=1, tl=0) nan

似乎他们唯一的区别是内存地址。

但是,当我将 NA_real_NaN 强制转换为字符时,它会返回,

> as.character(c(NaN, NA_real_))
[1] "NaN" NA

我知道它应该返回上述结果,因为NaN 不能是字符,它将被强制转换为"NaN",但NA_real 将被强制转换为NA_character_。但是考虑到他们的直觉是一样的,R 怎么可能为他们返回不同的结果呢?

提前感谢您的任何建议!

【问题讨论】:

    标签: r nan na


    【解决方案1】:

    NA 是一个统计数据完整性的概念:“缺失值”的概念。例如,如果您的数据来自填写表格的人,则错误条目或缺失条目将被视为NA

    NaN 是一个 numericalcomputational 概念:“不是数字”的东西。例如,0/0 是NAN,因为这个计算的结果是不确定的(但请注意,1/0 是Inf,或无穷大,同样-1/0 是-Inf)。

    R 内部处理这些概念的方式不是你应该关心的。

    【讨论】:

      【解决方案2】:

      嗯。首先,请记住 NA 是一个 R 概念,在 C 中没有等价物。因此,NA 需要在 C 中以不同方式表示。.Internal(inspect()) 没有做出这种区分的事实并不意味着它不是在其他地方制造的。事实上,.Internal(inspect()) 恰好使用Rprintf 来打印值的内部双浮点表示。而且,实际上,R NA 被编码为 C 浮点类型中的 NaN 值。

      其次,您观察到“它们的唯一区别是内存地址”。 - 所以呢?至少在概念上不同的内存地址完全足以区分 NA 和 NaN,不需要更多。

      但事实上,R 通过不同的途径区分这些值。这是可能的,因为IEEE 754 double precision floating point formatmultiple different representations of NaN,而 R 为 NA 保留了一个特定的:

      static double R_ValueOfNA(void)
      {
          /* The gcc shipping with Fedora 9 gets this wrong without
           * the volatile declaration. Thanks to Marc Schwartz. */
          volatile ieee_double x;
          x.word[hw] = 0x7ff00000;
          x.word[lw] = 1954;
          return x.value;
      }
      

      和:

      /* is a value known to be a NaN also an R NA? */
      int attribute_hidden R_NaN_is_R_NA(double x)
      {
          ieee_double y;
          y.value = x;
          return (y.word[lw] == 1954);
      }
      
      int R_IsNA(double x)
      {
          return isnan(x) && R_NaN_is_R_NA(x);
      }
      
      int R_IsNaN(double x)
      {
          return isnan(x) && ! R_NaN_is_R_NA(x);
      }
      

      (src/main/arithmetic.c)

      【讨论】:

      • 还值得一提的是文档中的一些内容:“使用 NA 的数值计算通常会导致 NA:一个可能的例外是也涉及 NaN,在这种情况下可能会导致(这可能取决于R 平台)。但是,这不能保证,未来的 CPU 和/或编译器可能会有不同的行为。这是因为 NA 中的 1954 值不能保证在所有操作中都保持不变。
      • @Konrad 感谢您的回复!它真的对我有很大帮助。但我对第二段感到困惑。当我们使用 .Internal(inspect(NaN)) 两次时,我们也会得到不同的内存地址。由于我以前没有学过 C,我可以认为新的 NaN 与以前的 NaN 存储在不同的位置,但它们在内部是相同的。所以我不确定为什么“不同的内存地址足以区分 NA 和 NaN”。任何帮助将不胜感激!
      • @YuliS 好的,这确实使它更难(仍然可以使用内存地址来区分值,例如通过内部维护哈希表,但这会使逻辑复杂化或低效)。我的回答中的第二段是在假设 NaNNA 文字值是单例的情况下编写的,即始终位于相同的内存地址。 R 不这样做的事实实际上有点令人惊讶(对此类对象使用相同的内存地址是一种相当频繁的内存优化)。
      • R_NaN_is_R_NA(double x) 没有检查x 的内存地址。它正在检查位序列,这在 IEEE 754 NaN 类型中有所不同。这就是 R 的 NaNNA_real_ 的区别。这些常量不能具有固定地址,因为双向量的元素在内存中是连续存储的。
      • @MikaelJagan 是的,我的回答已经说了这么多。特别是我并不是说地址用于来区分值,而是它们在概念上可以被使用。你是对的,这需要不连续的向量,这会带来问题——但它可以想象的(其他语言也可以做类似的事情)。
      猜你喜欢
      • 2016-03-19
      • 2013-07-23
      • 2021-11-29
      • 2023-03-17
      • 2013-02-23
      • 2017-10-08
      • 2021-01-09
      相关资源
      最近更新 更多