-3

IPv6 addresses are 128-bit unsigned integers under the hood, so their range of values is [0, 3.40 × 10^38]

A 128-bit register can store 2^128 (over 3.40 × 10^38) different values. The range of integer values that can be stored in 128 bits depends on the integer representation used. With the two most common representations, the range is 0 through 340,282,366,920,938,463,463,374,607,431,768,211,455 (2^128 − 1) for representation as an (unsigned) binary number, https://en.wikipedia.org/wiki/128-bit

A double-precision float variable in whatever language, though, can be as high as ±1.79769313486231570e+308 , so it definitely can assume all the values a 128-bit int can, and even more.

I'm sure there is a ready-to-use function/library/piece of code to convert from IPv6 => double. Can anyone post code to do that, or a link?

Thanks

Preferably PHP, but you can post code in other languages and i will translate to PHP.

P.S. i've read this related question Can double be used to store and safely retrieve 128 bit IPv6? but IMO the answers were wrong, because you don't need a variable with the same bits as the IPv6 address (128-bit). You just need it to be able to assume all the possible values an IPv6 can have. As i said above, a double can represent al the possible values of an 128-bit int and even more, despite it being just 64-bit.

How's that possible?

This is the magic of floating-point registers. They are more CPU-intensive to do calculations with compared to integer ones, but are more powerful.

EDIT: Why do i need this conversion: i have a MySQL table with IPv6 addresses defined as DECIMAL(39), which is a 39-digit int. I need to query that table by visitor's address if it is IPv6.

HelloWorld
  • 160
  • 2
  • 13
  • 5
    `double` can't store every unique values in the range. It's limited to a certain number of significant digits. If it fits in 64 bit it can **at most** represent `2^64` different possible values (otherwise at least 2 values would share the same bit representation at which point they cease to be distinct) which is far less than `2^128`. – François Andrieux Mar 12 '19 at 19:43
  • 1
    Is there any reason you can't use [`inet_pton`](http://php.net/manual/en/function.inet-pton.php), it doesn't return a double, but is that important? – Nigel Ren Mar 12 '19 at 19:45
  • 3
    Sounds like an xy question. Why do you think you need to convert ip's to doubles? – fstam Mar 12 '19 at 19:47
  • 1
    "double can represent al the possible values of an 128-bit int and even more, despite it being just 64-bit." no way. Forget all details about doubles and integers, then in 128-bit there are 2^128 different values in 64-bit there are only 2^64. Your question is based on a false premise, and it is rather unclear why you want a double in the first place – 463035818_is_not_an_ai Mar 12 '19 at 19:50
  • @Nigel and fstam Yes i need this conversion because i have a MySQL table with IPv6 addresses defined as DECIMAL(39), which is a 39-digit int. I need to query that table by visitor's address if it is IPv6. – HelloWorld Mar 12 '19 at 19:53
  • 2
    i think you should read up on information science *basics* before working any more in programming. please. – Franz Gleichmann Mar 12 '19 at 19:54
  • IP addresses are unisigned binary integers (whole numbers). That is how they are used by the networks, stored and used as 128-bit integers. The 128-bit integers are used in operations, such as bitwise AND and OR. Other representations cannot be properly manipulated. – Ron Maupin Mar 12 '19 at 20:41

1 Answers1

12

A double-precision float variable in whatever language, though, can be as high as ±1.79769313486231570e+308 , so it definitely can assume all the values a 128-bit int can, and even more.

This assumption is wrong. A double-precision float variable can not assume all the values a 128-bit int can.

This is because the floating point type in computer science has limited precision. Once you get to numbers greater than 2^52, you can no longer represent individual integers in that range. You're limited to 2^52, 2^52+2, 2^52+4, 2^52+6, ... until you reach 2^53, at which point you lose more precision, only representing values 2^53, 2^53+4, 2^53+8, 2^53+12, ...

So if, say, your IPv6 address is 2^52+1, a double would be incapable of representing it.

So no, it is not possible to represent the whole range of IPv6 addresses in the space defined by a double, 64-bit floating point value.

See Is Floating Point Math Broken? for a more detailed breakdown on how Floating Point math works in computers.


Part of your issue appears to be some confusion between types. A DECIMAL type in computer science is not the same kind of type as a double type. decimal types are usually some kind of BigNum implementation. They probably can store an entire IPv6 address, but it's not going to do it in only 64-bits. It'll use whatever quantity of bits is required by the database implementation (probably more than 128 bits, since decimal is usually designed to handle fixed-point math).

If you need to save an IPv6 address in a database, you might be able to get away with it with a decimal(39) type, but to be safe, you should be using one of these instead:

  • An explicitly sized 128-bit integer field
  • A 16-byte VARCHAR (or some other string-like field) that saves 8 bits per character
  • A 64-byte VARCHAR field that saves the IP Address in a Hexadecimal-encoded string (like how they are commonly represented).
  • A 22-byte VARCHAR field that saves the IP Address in a BASE64-encoded string
Xirema
  • 19,889
  • 4
  • 32
  • 68
  • Note: a 39-digit decimal number would require 130 bits to store as an integer, but as mysql does something funky for DECIMAL it's between 4 and 5 bytes. https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html#data-types-storage-reqs-numeric – Sammitch Mar 12 '19 at 20:32
  • 1
    Also the 16-byte representation should be stored as BIN or VARBIN to avoid being munged by encoding snafus. – Sammitch Mar 12 '19 at 20:33
  • @Sammitch The documentation you quoted suggests it would take 18 bytes to store a `DECIMAL(39)` number (39/9 == 4, 4*4 == 16, leftover is 3 digits requiring 2 additional bytes). – Xirema Mar 12 '19 at 20:35