如何检查std :: pow是否会溢出双倍

时间:2013-09-04 08:37:29

标签: c++ gmp pow

我有一个处理任意大网格的函数。由于使用std::pow,我需要计算另一个数字的幂的网格是否适合双精度。如果不能,我想采用不同的分支并使用gnu multiprecision库而不是普通的。

有没有快速查看是否:

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
}

我对checkPowFitsDouble感到非常难过;也许有一些我不知道的数学技巧。

4 个答案:

答案 0 :(得分:4)

除非它对性能至关重要,否则建议尝试并查看。如果它溢出双倍,std::pow将返回HUGE_VAL。因此类似于:

double val = std::pow(a, b);
if(val != HUGE_VAL) {
    ...
} else {
    mpz_t c; 
    //...
}

答案 1 :(得分:3)

您可以在测试中轻松使用反向功能:

if ( std::log( DBL_MAX ) / std::log( a ) < b ) {
    //  std::pow( a, b ) will not overflow...
} else {
}

做战俘可能同样好,看看是否合适 成功:

errno = 0;
double powab = std::pow( a, b );
if ( errno == 0 ) {
    //  std::pow succeeded (without overflow)
} else {
    //  some error (probably overflow) with std::pow.
}

只需计算std::log( a ),您就不会有太多时间。 (std::log( DBL_MAX )当然是一个常数,所以只需要 计算一次。)

答案 2 :(得分:2)

使用对数基数10,您可以推断出std:pow(a, b)log(a^b) = b log a个数字。然后,您可以轻松地查看它是否适合双精度值,这可以使值达到DBL_MAX。

但是,此方法执行额外的计算而不仅仅计算a^b一次。首先使用GMP测量版本,然后查看检查溢出是否实际上提供了任何可衡量和可重现的好处。

编辑:忽略这一点,std::pow已经返回一个适当的值,以防发生溢出,所以使用它。

答案 3 :(得分:2)

检查指数是否会溢出的常用技巧是使用对数。这个想法基于这些关系:

a^b <= m <=> log(a^b) <= log(m) <=> b * log(a) <= log(m) <=> b <= log(m) / log(a)

例如,

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";
}

这给出了这个想法。我希望这会有所帮助。