Use of 128-Bit Integer in C++

Abdul Mateen Feb 15, 2024
  1. Use of 128-Bit Integer in C++
  2. Importance of 128-Bit Integer
  3. Structure of Two 64-Bit Integers to Print 128-Bit Integer Using the sizeof() Method
  4. Structure of Two 64-Bit Integers to Print 128-Bit Integer in Hexadecimal Format and Individual Bytes in a Formatted Manner
  5. Conclusion
Use of 128-Bit Integer in C++

In this article, we will discuss 128-bit integers in C++. We will also see why we need it and the possible alternatives in C++.

Use of 128-Bit Integer in C++

The use of a 128-bit integer in C++ is primarily driven by the need to represent and manipulate very large integer values that cannot be accommodated within the range of standard integer types (e.g., 32-bit or 64-bit integers).

Within C++, various options exist for handling integers, ranging from the int data type to long, long int, and long long int, each with a 64-bit capacity. The maximum positive number that can be accommodated within these types is 9223372036854775807 (in hexadecimal 7FFFFFFFFFFFFFFF).

Consider the hexadecimal representation of 7; proceeding, the subsequent representation would be 8, characterized by the binary notation 1000, indicating the activation of the sign bit.

Subsequently, negative integers are encompassed within the range from -1 to -9223372036854775808. The value 9223372036854775807 is enough to address numerous storage and arithmetic operation requirements.

It’s important to note that while some compilers and platforms provide support for an int128_t type or equivalent, it’s not part of the C++ standard.

Consequently, developers may need to resort to external libraries, custom structures, or compiler-specific extensions to effectively handle 128-bit integers. The choice of implementation depends on the specific requirements and the level of portability desired for the code.

Importance of 128-Bit Integer

The importance of the 128-bit integer in programming, particularly in languages like C++, is underscored by its capacity to handle extremely large integer values that surpass the limitations of standard 32-bit or 64-bit integers.

It is crucial for precision, accommodating extensive numerical values, and performing arithmetic operations on large integers. The 128-bit integer’s versatility in representing both positive and negative values makes it a fundamental tool for addressing diverse computational challenges.

Despite not being standardized in C++, developers often utilize external libraries or custom structures to incorporate and manipulate 128-bit integers based on specific project needs. In essence, the 128-bit integer is essential for overcoming the limitations of conventional integer types and effectively handling vast numerical values in programming.

If there is a requirement for integers surpassing the capacity of 128 bits, then more storage than 128 bits would probably be required.

The result of the addition or multiplication of two big integers might need more bits. Therefore, in this case, implementing big integers might help solve the issue.

Structure of Two 64-Bit Integers to Print 128-Bit Integer Using the sizeof() Method

If the need is for storage only in using a 128-bit integer, one solution is to create a structure of two 64-bit integers or might take an int array of 8 elements or a char array of 16 elements.

This C++ code below defines a structure called Int128, which represents a 128-bit integer by splitting it into two 64-bit parts (low and high). The purpose of this code is to demonstrate the size of the Int128 structure in terms of memory consumption.

Example code:

#include <cstdint>
#include <iostream>

struct Int128 {
  uint64_t low;
  uint64_t high;
};

int main() {
  Int128 var;
  std::cout << "Size of Int128: " << sizeof(var) << " bytes\n";
  return 0;
}

In this code snippet, we start by including the <cstdint> header, which provides fixed-size integer types (uint64_t in this case) for improved portability across different systems. The <iostream> is the one that allows the use of input and output operations in the program.

Next, the struct Int128 { uint64_t low; uint64_t high; }; code defines a custom structure named Int128, which has two members: low and high, both of type uint64_t (unsigned 64-bit integer). This structure is intended to represent a 128-bit integer by storing it as two 64-bit parts.

For the variable declaration, Int128 var; declares a variable named var of type Int128. It allocates memory for an instance of the Int128 structure, which consists of two uint64_t members.

Lastly, the std::cout << "Size of Int128: " << sizeof(var) << " bytes\n"; outputs the size (in bytes) of the Int128 structure using sizeof(var). The sizeof operator returns the size, in bytes, of the specified type or object. The result is printed to the standard output using std::cout.

Output:

Size of Int128: 16 bytes

The output will be 16, which means 16x8=128 bits.

However, it is supported for specific processors, which are capable of holding 128-bits; otherwise, when you try to store a big integer, the compiler generates one of the following warnings:

 warning: overflow in implicit constant conversion
 warning: integer constant is too large for its type

Structure of Two 64-Bit Integers to Print 128-Bit Integer in Hexadecimal Format and Individual Bytes in a Formatted Manner

The C++ code below demonstrates the representation of a 128-bit integer using a custom structure called Int128. The 128-bit integer is split into two 64-bit parts (low and high).

The program then extracts the individual bytes of this 128-bit integer, prints the integer in hexadecimal format, and displays its individual bytes in a formatted manner.

Example code:

#include <cstdint>
#include <cstring>  // Include for memcpy
#include <iomanip>
#include <iostream>

struct Int128 {
  uint64_t low;
  uint64_t high;
};

int main() {
  // Define a 128-bit integer
  Int128 my128BitInteger = {0x123456789ABCDEF0, 0x123456789ABCDEF0};

  // Extract the individual bytes
  uint8_t bytes[16];
  std::memcpy(bytes, &my128BitInteger, sizeof(my128BitInteger));

  // Print the 128-bit integer
  std::cout << "128-bit integer: " << std::hex << std::setfill('0')
            << std::setw(16) << my128BitInteger.high << std::setw(16)
            << my128BitInteger.low << std::dec << std::endl;

  // Print the individual bytes
  std::cout << "Bytes: ";
  for (int i = 0; i < 16; ++i) {
    std::cout << std::setfill('0') << std::setw(2) << std::hex
              << static_cast<int>(bytes[i]) << " ";
  }
  std::cout << std::endl;

  return 0;
}

The code includes necessary headers for input/output operations (iostream), formatting output (iomanip), fixed-width integer types (cstdint), and memory manipulation functions (cstring).

The Int128 structure represents a 128-bit integer by dividing it into two parts (low and high), each of type uint64_t.

For the main function of the code snippet, an instance of Int128 named my128BitInteger is created and initialized with specific values. The memcpy function is used to copy the content of the my128BitInteger structure into a byte array (bytes).

The program then prints the original 128-bit integer in hexadecimal format and displays the individual bytes in a formatted manner.

Output:

128-bit integer: 123456789abcdef0123456789abcdef0
Bytes: f0 de bc 9a 78 56 34 12 f0 de bc 9a 78 56 34 12

The output shows the 128-bit integer and its individual bytes, providing insight into the memory representation of the 128-bit integer.

Conclusion

In this exploration of 128-bit integers in C++, we delve into their necessity for representing and manipulating extremely large integer values that surpass the limitations of standard 32-bit or 64-bit integers.

While not standardized in C++, various approaches exist, from custom structures like Int128 to external libraries or compiler-specific extensions.

The importance of 128-bit integers lies in their capacity to handle vast numerical values, crucial for precision and arithmetic operations.

The code samples illustrate alternatives, such as the structure of two 64-bit integers, shedding light on the challenges and solutions associated with handling 128-bit integers in C++.

Related Article - C++ Integer