아래 표에서 처럼 C/C++에서 지원하는 정수 타입의 자료형(long long 또는 unsigned long long)은 최대 8byte입니다. 그렇다면 8byte(32bit)를 초과하는 정수는 어떤 자료형을 통해 관리해야할까요?

자료형 크기 범위
long long 8 byte -9,223,372,036,854,775,807 ~ 9,223,372,036,854,775,807
unsigned long long 8 byte 0 ~ 18,446,744,073,709,551,615

Java에서는 이처럼 8byte를 초과하는 큰 정수들을 처리하기 위한 BigInteger라는 클래스를 제공하고 있습니다.

  • java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String left = "18446744073709551615";
String right = "18446744073709551615";

// 문자열 타입의 첫번째 인자 값을 두번째 인자로 지정된 N진수로 변환해줌
BigInteger bi_left = new BigInteger(left, 10);
BigInteger bi_right = new BigInteger(right, 10);
BigInteger output = bi_left.add(bi_right);
System.out.println("output(dec): " + output.toString());

StringBuilder sb = new StringBuilder();
byte[] ba = output.toByteArray();
for(final byte b: ba)
{
sb.append(String.format("0x%02x ", b&0xff));
}
System.out.println("output(hex): " + sb);
1
2
output(dec) : 36893488147419103230
output(hex) : 0x01 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xfe

불행히도 C/C++ 내장형 타입 중에는 8byte를 초과하는 자료형이 존재하지 않습니다. stackoverflow를 찾아보니 직접 구현을 해서 사용하거나 외부 라이브러리(Gmplib, bigint)를 사용하라고 하는데..
입맛에 맞게 사용하기 위해 boost::multiprecision을 활용하여 간략하게 구현해보았습니다.

  • cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
#include <cinttypes>

#include <algorithm>
#include <boost/multiprecision/cpp_int.hpp>

int main()
{
std::string left = "18446744073709551615";
std::string right = "18446744073709551615";

// 18446744073709551615는 10진수로 표현된 20자리 정수 값이며 풀어써보면 (1*10^19) + (8*10^18) + (4*10^17) + ... + (1*10^1) + (5*10^0) 입니다.
// 해당 과정을 구현한 코드는 아래와 같습니다.
//
// 사실 10진수 정수의 경우에는 문자열 타입의 값을 boost::multiprecision::cpp_int 생성자의 인자로 전달하면 쉽게 변환하여 연산이 가능합니다.
// std::string value = "18446744073709551615";
// boost::multiprecision::cpp_int bi_value(value);
//
// 하지만 Java의 BigInteger 처럼 사용자가 직접 특정 진수를 지정하여 변환할 수는 없었기때문에 진수 변환 로직을 추가했습니다.
boost::multiprecision::cpp_int bi_left(0);
int len = left.length();
for (int i = 0; i < len; ++i)
{
std::string tmp_str;
tmp_str.append(1, left[i]);
bi_left += (boost::multiprecision::pow(boost::multiprecision::cpp_int(10), len - i - 1) * std::strtoimax(tmp_str.c_str(), nullptr, 10));
}

boost::multiprecision::cpp_int bi_right(0);
len = right.length();
for (int i = 0; i < len; ++i)
{
std::string tmp_str;
tmp_str.append(1, left[i]);
bi_right += (boost::multiprecision::pow(boost::multiprecision::cpp_int(10), len - i - 1) * std::strtoimax(tmp_str.c_str(), nullptr, 10));
}

boost::multiprecision::cpp_int output = bi_left + bi_right;
std::cout << "output(dec): " << output << std::endl;

using byte_array_type = std::vector<unsigned char>;
byte_array_type ba_output;
boost::multiprecision::export_bits(output, std::back_inserter(ba_output), 8);

printf("output(hex): ");
int ba_output_len = ba_output.size();
for(int i = 0; i < ba_output_len; ++i)
{
printf("0x%02x ", ba_output[i]);
}

return 0;
}
1
2
output(dec) : 36893488147419103230
output(hex) : 0x01 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xfe

Reference