What is an efficient way get the digit count of a boost::multiprecision::cpp_int
? The log10()
function is apparently not compatible with multiprecision integers and I can't figure out any other way to do this.
Asked
Active
Viewed 1,027 times
3

user1892304
- 617
- 1
- 6
- 11
3 Answers
3
You can use .str().size()
.
const cpp_int n = cpp_int("123456789") * cpp_int("987654321");
const size_t digits = n.str().size(); // digits == 18
It looks wasteful, but faster than either log10 or dividing by 10.

Tsuda Kageyu
- 31
- 3
-
2Is it faster? That's a very bold claim. Especially in context of, say, https://stackoverflow.com/questions/71630251/boost-multiprecision-cpp-int-output-to-string-very-slow – sehe Mar 27 '22 at 02:08
0
If conversion to cpp_dec_float1 is not desired (I'm guessing not) you could divide by 10:
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using Int = boost::multiprecision::cpp_int;
using Float = boost::multiprecision::cpp_dec_float_50;
int main() {
Int demo("12345678912345678");
int digits = 0;
for (Int tmp = abs(demo); tmp > 0; tmp /= 10)
digits += 1;
std::cout << digits << ", " << ceil(log10(Float(demo))) << "\n";
}
This could perhaps be optimized for very large integers (by starting with a 1000000 divisor, e.g. until the value becomes smaller than that divisor). I'd let my profiler guide such optimizations (since it's easy to get the wrong result).
0
If you are using boost::multiprecision::cpp_int then boost::multiprecision::log10 should be the most performant way. Don't do the division or to str as suggested here since it's very slow.
input: 1'000'000 ^ 1'000
calc time: 0s
log digits: 6001, log time: 0s
str digits: 6001, str time: 0.001s
div digits: 6001, div time: 0.022s
input: 1'000'000 ^ 10'000
calc time: 0.004s
log digits: 60001, log time: 0.003s
str digits: 60001, str time: 0.1s
div digits: 60001, div time: 1.808s
input: 1'000'000 ^ 100'000
calc time: 0.374s
log digits: 600001, log time: 0.436s
str digits: 600001, str time: 10.143s
div digits: 600001, div time: 183.218s
input: 1'000'000 ^ 1'000'000
log digits: 6000001, log time: 48.968s
Others not tested. The str version should be at ~15-20 minutes and div probably at 5 hours.
test code:
#include <iostream>
#include <chrono>
#include <boost/multiprecision/gmp.hpp>
#include <boost/multiprecision/cpp_int.hpp>
int main() {
std::chrono::steady_clock::time_point calcStart = std::chrono::steady_clock::now();
boost::multiprecision::cpp_int x = boost::multiprecision::pow(boost::multiprecision::cpp_int(1'000'000), 1'000);
std::chrono::steady_clock::time_point calcEnd_logStart = std::chrono::steady_clock::now();
boost::multiprecision::cpp_int digits = boost::multiprecision::log10(x.convert_to<boost::multiprecision::mpf_float_50>()).convert_to<boost::multiprecision::cpp_int>() + 1;
std::chrono::steady_clock::time_point logEnd_strStart = std::chrono::steady_clock::now();
size_t strDigits = x.str().size();
std::chrono::steady_clock::time_point strEnd_divStart = std::chrono::steady_clock::now();
uint64_t divCnt = 1;
while (x >= 10) {
x /= 10;
divCnt++;
}
std::chrono::steady_clock::time_point divEnd = std::chrono::steady_clock::now();
std::cerr << "calc time: " << std::chrono::duration_cast<std::chrono::milliseconds> (calcEnd_logStart - calcStart).count() / 1000.0 << "s" << std::endl;
std::cerr << "log digits: " << digits << ", log time: " << std::chrono::duration_cast<std::chrono::milliseconds> (logEnd_strStart - calcEnd_logStart).count() / 1000.0 << "s" << std::endl;
std::cerr << "str digits: " << strDigits << ", str time: " << std::chrono::duration_cast<std::chrono::milliseconds> (strEnd_divStart - logEnd_strStart).count() / 1000.0 << "s" << std::endl;
std::cerr << "div digits: " << divCnt << ", div time: " << std::chrono::duration_cast<std::chrono::milliseconds> (divEnd - strEnd_divStart).count() / 1000.0 << "s" << std::endl;
return 0;
}

Richard
- 43
- 4