diff --git a/bigint.h b/bigint.h index 9a7035a..43725b3 100644 --- a/bigint.h +++ b/bigint.h @@ -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); @@ -381,6 +386,7 @@ namespace BigInt { } static std::vector string_to_vector(std::string input); + static std::vector hex_to_vector(std::string input); static std::string vector_to_string(const std::vector& input); @@ -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; } @@ -844,6 +864,38 @@ namespace BigInt { return result; } + inline std::vector bigint::hex_to_vector(std::string input) { + // Strip "0x" prefix + const std::string hex = input.substr(2); + + std::vector 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(result.size()) - 1; i >= 0; --i) { + const unsigned long long val = static_cast(result[i]) * 16 + carry; + result[i] = static_cast(val % static_cast(MAX_SIZE)); + carry = val / static_cast(MAX_SIZE); + } + // carry <= 15 < MAX_SIZE, so this loop runs at most once + while (carry > 0) { + result.insert(result.begin(), static_cast(carry % static_cast(MAX_SIZE))); + carry /= static_cast(MAX_SIZE); + } + } + + return result; + } + inline std::string bigint::vector_to_string(const std::vector& input) { std::stringstream ss; bool first = true; diff --git a/tests/test.cpp b/tests/test.cpp index 041a796..2d86402 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -99,8 +99,10 @@ class BigInt_ModParamTest : public ::testing::TestWithParam{}; TEST(Test_BigInt, Invalid_Tests) { EXPECT_THROW(bigint('a'), std::runtime_error); + EXPECT_THROW(bigint('z'), std::runtime_error); EXPECT_THROW(bigint(static_cast(0)), std::runtime_error); EXPECT_THROW(bigint(static_cast(-1)), std::runtime_error); + EXPECT_THROW(bigint(static_cast(99)), std::runtime_error); EXPECT_THROW(bigint("a"), std::runtime_error); EXPECT_THROW(bigint("?"), std::runtime_error); EXPECT_THROW(bigint(""), std::runtime_error); @@ -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; @@ -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); @@ -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) {