diff --git a/CMakeLists.txt b/CMakeLists.txt index 22bec14..b91177f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.15) -project(BigIntegerCpp VERSION 1.1) +project(BigIntegerCpp VERSION 1.2) set(CMAKE_CXX_STANDARD 17) diff --git a/bindings/python/python-bindings.cpp b/bindings/python/python-bindings.cpp index dc77612..2e24349 100644 --- a/bindings/python/python-bindings.cpp +++ b/bindings/python/python-bindings.cpp @@ -67,7 +67,7 @@ py::int_ to_py_int(const BigInteger& value, bool is_signed = true, bool is_bigen return py::reinterpret_steal(obj); } -static constexpr auto VERSION_BINDINGS = "1.2.3"; +static constexpr auto VERSION_BINDINGS = "1.2.4"; PYBIND11_MODULE(pybiginteger, m) { m.doc() = "A C++ port of the C# BigInteger class"; @@ -329,5 +329,6 @@ PYBIND11_MODULE(pybiginteger, m) { }, py::arg("value"), py::arg("base_value")) .def_static("log10", &BigInteger::log10, py::arg("value")) .def_static("log10", [](py::int_& value) { return BigInteger::log10(to_biginteger(value)); }, py::arg("value")) + .def("get_bit_Length", &BigInteger::get_bit_length) .def_property_readonly("sign", &BigInteger::sign); } \ No newline at end of file diff --git a/include/public/bigintegercpp/BigInteger.h b/include/public/bigintegercpp/BigInteger.h index 134cdc6..f15928d 100644 --- a/include/public/bigintegercpp/BigInteger.h +++ b/include/public/bigintegercpp/BigInteger.h @@ -174,6 +174,8 @@ class BigInteger { int get_byte_count(bool isUnsigned = false) const; + uint64_t get_bit_length() const; + static bool double_IsFinite(double value); static bool double_IsInfinity(double value); diff --git a/src/BigInteger.cpp b/src/BigInteger.cpp index 7736400..a871090 100644 --- a/src/BigInteger.cpp +++ b/src/BigInteger.cpp @@ -1193,6 +1193,62 @@ int BigInteger::get_byte_count(bool isUnsigned) const { return bytesWritten; } +unsigned int leading_zeros_count(unsigned int value) { + if (value == 0) { + return 32; + } + static const char debruijn32[32] = { + 0, 31, 9, 30, 3, 8, 13, 29, 2, 5, 7, 21, 12, 24, 28, 19, + 1, 10, 4, 14, 6, 22, 25, 20, 11, 15, 23, 26, 16, 27, 17, 18 + }; + value |= value >>1; + value |= value >>2; + value |= value >>4; + value |= value >>8; + value |= value >>16; + value++; + return debruijn32[value * 0x076be629>>27]; +} + +uint64_t BigInteger::get_bit_length() const { + assert_valid(); + + unsigned int highValue; + int bitsArrayLength; + int sign = _sign; + + if (_bits.empty()) { + bitsArrayLength = 1; + highValue = (unsigned int)(sign < 0 ? -sign : sign); + } else { + bitsArrayLength = _bits.size(); + highValue = _bits[bitsArrayLength - 1]; + } + + long bitLength = bitsArrayLength * 32L - leading_zeros_count(highValue); + + if (sign >= 0) + return bitLength; + + // When negative and IsPowerOfTwo, the answer is (bitLength - 1) + + // Check highValue + if ((highValue & (highValue - 1)) != 0) + return bitLength; + + // Check the rest of the bits (if present) + for (int i = bitsArrayLength - 2; i >= 0; i--) + { + // bits array is always non-null when bitsArrayLength >= 2 + if (_bits[i] == 0) + continue; + + return bitLength; + } + + return bitLength - 1; +} + byte_array BigInteger::to_byte_array(bool isUnsigned, bool isBigEndian) const { int ignored = 0; return this->to_byte_array(GetBytesMode::AllocateArray, isUnsigned, isBigEndian, &ignored);