首页 > 解决方案 > 将 IPv6 地址转换为 64 位双精度

问题描述

IPv6 地址是 128 位无符号整数,因此它们的取值范围是 [0, 3.40 × 10^38]

一个 128 位寄存器可以存储 2^128(超过 3.40 × 10^38)个不同的值。可以存储在 128 位中的整数值的范围取决于所使用的整数表示。使用两种最常见的表示形式,范围是 0 到 340,282,366,920,938,463,463,374,607,431,768,211,455 (2^128 - 1) 表示为(无符号)二进制数, https://en.wikipedia.org/wiki/128-bit

但是,任何语言的双精度浮点变量都可以高达 ±1.79769313486231570e+308 ,因此它绝对可以假设 128 位 int 可以的所有值,甚至更多。

我确信有一个现成的函数/库/一段代码可以从 IPv6 => double 转换。任何人都可以发布代码来做到这一点,或者链接?

谢谢

最好是 PHP,但你可以发布其他语言的代码,我会翻译成 PHP。

PS 我读过这个相关的问题Can double be used to store and saferetrieve 128 bit IPv6? 但 IMO 的答案是错误的,因为您不需要与 IPv6 地址(128 位)具有相同位的变量。您只需要它能够假设 IPv6 可以具有的所有可能值。正如我上面所说,尽管它只是 64 位,但 double 可以表示 128 位 int 的所有可能值,甚至更多。

这怎么可能?

这就是浮点寄存器的魔力。与整数计算相比,它们在计算时占用更多 CPU,但功能更强大。

编辑:为什么我需要这种转换:我有一个 MySQL 表,其中 IPv6 地址定义为 DECIMAL(39),它是一个 39 位整数。如果是 IPv6,我需要通过访问者的地址查询该表。

标签: phpc++floating-pointipv6

解决方案


但是,任何语言的双精度浮点变量都可以高达 ±1.79769313486231570e+308 ,因此它绝对可以假设 128 位 int 可以的所有值,甚至更多。

这个假设是错误的。双精度浮点变量不能假定 128 位 int 可以的所有值。

这是因为计算机科学中的浮点类型精度有限。一旦得到大于 2^52 的数字,就不能再表示该范围内的单个整数。你被限制在 2^52、2^52+2、2^52+4、2^52+6、...直到你达到 2^53,此时你失去了更多的精度,只代表值 2^ 53, 2^53+4, 2^53+8, 2^53+12, ...

因此,如果您的 IPv6 地址是 2^52+1,adouble将无法表示它。

所以不,不可能在double64 位浮点值定义的空间中表示整个 IPv6 地址范围。

请参阅浮点数学是否损坏?有关浮点数学如何在计算机中工作的更详细的细分。


您的部分问题似乎是类型之间的一些混淆。计算机科学中的DECIMAL类型与double类型不同。decimal类型通常是某种 BigNum 实现。他们可能可以存储完整的 IPv6 地址,但它不会仅以 64 位存储。它将使用数据库实现所需的任何位数(可能超过 128 位,因为decimal通常设计用于处理定点数学)。

如果您需要将 IPv6 地址保存在数据库中,您可能可以使用类型来摆脱它decimal(39),但为了安全起见,您应该使用以下其中之一:

  • 显式大小的 128 位整数字段
  • 一个 16 字节VARCHAR(或其他类似字符串的字段),每个字符节省 8 位
  • 一个 64 字节的VARCHAR字段,将 IP 地址保存在十六进制编码的字符串中(就像它们通常的表示方式一样)。
  • VARCHAR将 IP 地址保存在 BASE64 编码字符串中的 22 字节字段

推荐阅读