问题
I have a function that deals with arbitrarily large grids. I need to compute if a grid to the power of another number will fit into a double due to using std::pow
. If it cannot, I want to take a different branch and use gnu multiprecision library instead of normal.
Is there a quick way to see if:
int a = 1024;
int b = 0-10;
if(checkPowFitsDouble(a, b)) {
long c = static_cast<long>(std::pow(a, b)); //this will only work if b < 6
} else {
mpz_t c; //yada yada gmp
}
I am completely stumped on checkPowFitsDouble; perhaps there is some math trick I don't know of.
回答1:
A common trick to check whether exponentiations will overflow uses logarithms. The idea is based on these relationships:
a^b <= m <=> log(a^b) <= log(m) <=> b * log(a) <= log(m) <=> b <= log(m) / log(a)
For instance,
int a = 1024;
for (int b = 0; b < 10; ++b) {
if (b * std::log(a) < std::log(std::numeric_limits<long>::max())) {
long c = std::pow(a, b);
std::cout << c << '\n';
}
else
std::cout << "overflow\n";
}
This gives the idea. I hope this helps.
回答2:
Unless it's particularly performance-critical, the suggestion would be to try it and see. If it overflows a double, std::pow
will return HUGE_VAL
. Hence something like:
double val = std::pow(a, b);
if(val != HUGE_VAL) {
...
} else {
mpz_t c;
//...
}
回答3:
You can easily use the reverse functions in the test:
if ( std::log( DBL_MAX ) / std::log( a ) < b ) {
// std::pow( a, b ) will not overflow...
} else {
}
It might be just as good to just do the pow, and see if it succeeds:
errno = 0;
double powab = std::pow( a, b );
if ( errno == 0 ) {
// std::pow succeeded (without overflow)
} else {
// some error (probably overflow) with std::pow.
}
You won't gain much time by just calculating std::log( a )
.
(std::log( DBL_MAX )
is, of course, a constant, so only needs
to be calculated once.)
回答4:
With a logarithm base 10, you can deduce that std:pow(a, b)
has log(a^b) = b log a
digits. You can then trivially see if it fits a double, which can fit values up to DBL_MAX.
However, this method performs additional computation than just computing a^b
once. Measure a version with GMP first and see if checking for overflow actually provides any measurable and reproducible benefits.
EDIT: Ignore this, std::pow
already returns an appropriate value in case an overflow occurs, so use that.
来源:https://stackoverflow.com/questions/18609085/how-can-i-check-if-stdpow-will-overflow-double