【问题标题】:Converting IPv6 addresses to 64-bit double将 IPv6 地址转换为 64 位双精度
【发布时间】:2019-03-12 19:42:01
【问题描述】:

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。

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

这怎么可能?

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

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

【问题讨论】:

  • double 无法存储范围内的每个唯一值。它仅限于一定数量的有效数字。如果它适合 64 位,则它最多可以表示 2^64 不同的可能值(否则至少 2 个值将共享相同的位表示,此时它们不再不同),远远小于2^128.
  • 有什么原因不能使用inet_pton,它不会返回双精度值,但这很重要吗?
  • 听起来像是一个 xy 问题。为什么您认为需要将 ip 转换为双精度值?
  • "double 可以表示 128 位 int 的所有可能值,甚至更多,尽管它只是 64 位。"没门。忘记关于双精度和整数的所有细节,那么在 128 位中有 2^128 个不同的值,在 64 位中只有 2^64。你的问题是基于一个错误的前提,而且还不清楚为什么你首先想要一个双倍
  • 我认为你应该先阅读信息科学的基础,然后再从事编程工作。请。

标签: php c++ floating-point ipv6


【解决方案1】:

不过,任何语言的双精度浮点变量都可以高达 ±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,double 将无法表示它。

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

请参阅Is Floating Point Math Broken?,了解有关浮点数学在计算机中如何工作的更详细细分。


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

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

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

【讨论】:

  • 注意:一个 39 位十进制数需要 130 位来存储为整数,但由于 mysql 为 DECIMAL 做了一些时髦的事情,它在 4 到 5 个字节之间。 dev.mysql.com/doc/refman/8.0/en/…
  • 另外 16 字节的表示应该存储为 BIN 或 VARBIN 以避免被编码混乱。
  • @Sammitch 您引用的文档表明存储 DECIMAL(39) 数字需要 18 个字节(39/9 == 4、4*4 == 16,剩余的 3 位数字需要 2 个额外字节)。
猜你喜欢
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 2010-10-19
  • 1970-01-01
  • 2011-09-18
相关资源
最近更新 更多