将IPv6地址转换为64位双精度

问题描述 投票:-3回答:1

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可以拥有的所有可能值。正如我上面所说,double可以表示128位int的可能值,甚至更多,尽管它只是64位。

怎么可能?

这是浮点寄存器的神奇之处。与整数计算相比,它们更耗费CPU来进行计算,但功能更强大。

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

php c++ floating-point ipv6
1个回答
11
投票

不过,任何语言的双精度浮点变量都可以高达±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字段,用于在BASE64编码的字符串中保存IP地址
© www.soinside.com 2019 - 2024. All rights reserved.