首页 > 解决方案 > 为什么 NaN 和 Inf - Inf 的哈希值不同?

问题描述

我经常使用这个散列函数,即记录数据帧的值。想看看能不能破解。为什么这些哈希值不相同?

这需要摘要包。

纯文本输出:

> digest(Inf-Inf)
[1] "0d59b2dae9351c1ce6c76133295322d7"
> digest(NaN)
[1] "4e9653ddf814f0d16b72624aeb85bc20"
> digest(1)
[1] "6717f2823d3202449301145073ab8719"
> digest(1 + 0)
[1] "6717f2823d3202449301145073ab8719"
> digest(5)
[1] "5e338704a8e069ebd8b38ca71991cf94"
> digest(sum(1, 1, 1, 1, 1))
[1] "5e338704a8e069ebd8b38ca71991cf94"
> digest(1^0)
[1] "6717f2823d3202449301145073ab8719"
> 1^0
[1] 1
> digest(1)
[1] "6717f2823d3202449301145073ab8719"

额外的怪异。等于 NaN 的计算具有相同的哈希值,但 NaN 的哈希值不等价:

> Inf - Inf
[1] NaN
> 0/0
[1] NaN
> digest(Inf - Inf)
[1] "0d59b2dae9351c1ce6c76133295322d7"
> digest(0/0)
[1] "0d59b2dae9351c1ce6c76133295322d7"
> digest(NaN)
[1] "4e9653ddf814f0d16b72624aeb85bc20"    

标签: rmathhashdigest

解决方案


tl; dr这与 s 如何NaN以二进制表示的非常深入的细节有关。你可以通过使用来解决它digest(.,ascii=TRUE)...

跟进@Jozef 的回答:注意粗体数字...

> 基础::序列化(Inf-Inf,连接 = NULL)
[1] 58 0a 00 00 00 03 00 03 06 00 00 03 05 00 00 00 00 05 55 54 46 2d 38 00 00
[26] 00 0e 00 00 00 01 ff f8 00 00 00 00 00 00
> 基础::序列化(NaN,连接 = NULL)
[1] 58 0a 00 00 00 03 00 03 06 00 00 03 05 00 00 00 00 05 55 54 46 2d 38 00 00
[26] 00 0e 00 00 00 01 7f f8 00 00 00 00 00 00

或者,使用pryr::bytes()...

> bytes(NaN)
[1] "7F F8 00 00 00 00 00 00"
> bytes(Inf-Inf)
[1] "FF F8 00 00 00 00 00 00"

关于浮点格式/NaNs 的维基百科文章说:

浮点运算的某些运算是无效的,例如取负数的平方根。达到无效结果的行为称为浮点异常。异常结果由称为 NaN 的特殊代码表示,表示“非数字”。IEEE 754-1985 中的所有 NaN 都具有以下格式:

  • 符号 = 0 或 1。
  • 有偏指数 = 所有 1 位。
  • 分数 = 除所有 0 位之外的任何内容(因为所有 0 位都表示无穷大)。

符号是第一位;指数是接下来的 11 位;小数部分是最后 52 位。将上面给出的前四个十六进制数字转换为二进制,Inf-Inf1111 1111 1111 0100(符号=1;根据需要,指数全为一;分数以 开头0100) ,NaN而是0111 1111 1111 0100(相同,但符号=0)。

要了解为什么 Inf-Inf最终以符号位 1 和NaN符号位 0 结尾,您可能必须更深入地研究在此平台上实现浮点运算的方式......

可能值得在摘要 GitHub 存储库上提出一个关于此的问题;我想不出一种优雅identical(x,y)的方法来做到这一点,但在 R 中的对象应该具有相同的哈希值似乎是合理的TRUE......请注意,通过(default ) 参数identical()特别忽略了位模式中的这些差异:single.NATRUE

single.NA:逻辑上表示概念上是否只有一个数字“NA”和一个“NaN”;'single.NA = FALSE' 区分位模式。

在 C 代码中,看起来 R 只是使用 C 的!=运算符来比较NaN,除非启用按位比较,在这种情况下,它会显式检查内存位置的相等性:请参阅此处。也就是说,C 的比较运算符似乎将不同类型的NaN值视为等价的......


推荐阅读