NA_real_ 和 NaN 之间的区别

问题描述 投票:0回答:2

当我使用

.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
2个回答
18
投票

嗯。首先,请记住

NA
是一个 R 概念,在 C 中没有对应的概念。因此,必然需要在 C 中以不同的方式表示
NA
。事实上,
.Internal(inspect())
没有做出这种区分并不意味着它不是其他地方制造的。事实上,恰巧
.Internal(inspect())
使用
Rprintf
来打印值的内部双浮点表示。事实上,R NA 被编码为 C 浮点类型中的 NaN 值。

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

但事实上,R 通过不同的途径来区分这些值。这是可能的,因为 IEEE 754 双精度浮点格式 具有 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;
}

地点:

typedef union
{
    double value;
    unsigned int word[2];
} ieee_double;

并且

hw
lw
分别具有值 0 和 1(其值取决于平台 endianness)。

而且,此外:

/* 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
)


9
投票

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

NaN
是一个数值计算概念:“不是数字”的东西。例如 0/0 是
NAN
,因为此计算的结果是未定义的(但请注意,1/0 是
Inf
,或无穷大,类似地 -1/0 是
-Inf
)。

R 在内部处理这些概念的方式不是您应该关心的事情。

© www.soinside.com 2019 - 2024. All rights reserved.