Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions bigint.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ namespace BigInt {
throw std::runtime_error("Invalid Big Integer.");
is_neg = true;
}
else if (s[0] == '0' && s[1] == 'x') {
// Hex string
is_neg = false;
vec = hex_to_vector(s);
}
else {
is_neg = false;
vec = string_to_vector(s);
Expand Down Expand Up @@ -381,6 +386,7 @@ namespace BigInt {
}

static std::vector<long long> string_to_vector(std::string input);
static std::vector<long long> hex_to_vector(std::string input);

static std::string vector_to_string(const std::vector<long long>& input);

Expand Down Expand Up @@ -450,12 +456,26 @@ namespace BigInt {


inline bool bigint::is_bigint(const std::string& s) {
if (s.empty() || (s.length() > 1 && s[0] == '0'))
if (s.empty())
return false;

// Check for leading negative sign
if (s[0] == '-') {
return s.find_first_not_of("0123456789", 1) == std::string::npos;
if (s.length() == 1) return false;
// Recursively validate the rest as a positive bigint
// Note: leading zeros check still applies to the magnitude
return is_bigint(s.substr(1));
}

// Check for hex string "0x..."
if (s.length() > 2 && s[0] == '0' && s[1] == 'x') {
return s.find_first_not_of("0123456789abcdefABCDEF", 2) == std::string::npos;
}

// Reject leading zeros for decimal numbers
if (s.length() > 1 && s[0] == '0')
return false;

return s.find_first_not_of("0123456789", 0) == std::string::npos;
}

Expand Down Expand Up @@ -844,6 +864,38 @@ namespace BigInt {
return result;
}

inline std::vector<long long> bigint::hex_to_vector(std::string input) {
// Strip "0x" prefix
const std::string hex = input.substr(2);

std::vector<long long> result = {0};

for (const char c : hex) {
unsigned long long digit;
if (c >= '0' && c <= '9') digit = c - '0';
else if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
else throw std::runtime_error("Invalid hex character.");

// Multiply current value by 16 and add digit.
// Max intermediate value: (MAX_SIZE-1)*16+15 = 15,999,999,999,999,999,999
// which fits in unsigned long long (max ~18.4 * 10^18).
unsigned long long carry = digit;
for (int i = static_cast<int>(result.size()) - 1; i >= 0; --i) {
const unsigned long long val = static_cast<unsigned long long>(result[i]) * 16 + carry;
result[i] = static_cast<long long>(val % static_cast<unsigned long long>(MAX_SIZE));
carry = val / static_cast<unsigned long long>(MAX_SIZE);
}
// carry <= 15 < MAX_SIZE, so this loop runs at most once
while (carry > 0) {
result.insert(result.begin(), static_cast<long long>(carry % static_cast<unsigned long long>(MAX_SIZE)));
carry /= static_cast<unsigned long long>(MAX_SIZE);
}
}

return result;
}

inline std::string bigint::vector_to_string(const std::vector<long long>& input) {
std::stringstream ss;
bool first = true;
Expand Down
12 changes: 12 additions & 0 deletions tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ class BigInt_ModParamTest : public ::testing::TestWithParam<TestCase>{};

TEST(Test_BigInt, Invalid_Tests) {
EXPECT_THROW(bigint('a'), std::runtime_error);
EXPECT_THROW(bigint('z'), std::runtime_error);
EXPECT_THROW(bigint(static_cast<char>(0)), std::runtime_error);
EXPECT_THROW(bigint(static_cast<char>(-1)), std::runtime_error);
EXPECT_THROW(bigint(static_cast<char>(99)), std::runtime_error);
EXPECT_THROW(bigint("a"), std::runtime_error);
EXPECT_THROW(bigint("?"), std::runtime_error);
EXPECT_THROW(bigint(""), std::runtime_error);
Expand All @@ -121,6 +123,8 @@ TEST(Test_BigInt, Invalid_Tests) {

TEST(Test_BigInt, Creation_Tests) {
int my_int = 100;
unsigned int hex_int = 0xDEADBEEF;
int neg_hex_int = -0xBEEF;
long my_long = 100;
long long my_longlong = 100;
long long my_longlong2 = LLONG_MAX;
Expand All @@ -131,10 +135,15 @@ TEST(Test_BigInt, Creation_Tests) {
std::string my_string = "100";
std::string my_string3 = "-9223372036854775808";
std::string my_string4 = "-9223372036854775809";
std::string hex_string = "0xDEADBEEF0FF1CEF0CACC1A";
std::string neg_hex_string = "-0xBEEF";

EXPECT_EQ(bigint(my_int), 100);
EXPECT_EQ(bigint(-my_int), -100);

EXPECT_EQ(bigint(hex_int), 3735928559);
EXPECT_EQ(bigint(neg_hex_int), -48879);

EXPECT_EQ(bigint(my_long), 100);
EXPECT_EQ(bigint(-my_long), -100);

Expand All @@ -153,6 +162,9 @@ TEST(Test_BigInt, Creation_Tests) {
EXPECT_EQ(bigint(my_string), "100");
EXPECT_EQ(bigint(my_string3), "-9223372036854775808");
EXPECT_EQ(bigint(my_string4), "-9223372036854775809");

EXPECT_EQ(bigint(hex_string), "269202023463611101042363418");
EXPECT_EQ(bigint(neg_hex_string), "-48879");
}

TEST(Test_BigInt, Unary_Tests) {
Expand Down
Loading