为了检查double是否为2的幂,我找到了以下代码:
unsigned long long int &p= *(unsigned long long int *) &x;
unsigned int exp= (p >> 52) & 0x7FF;
if ( exp == 0 || exp == 0x7FF ) return false;
return (p & 0xFFFFFFFFFFFFFULL) == 0;
但是,它无法通过某些体系结构的基本测试。我猜那是因为整数的长度不同。因此,我试图找出一种不进行位操作的简单替代方案:
bool isPot(double a ){
return a==0.? false : (1./a)*a==1.;
}
假设数字除以非2的幂会在尾数中生成无限数字,因此,由于值被截断,因此乘以其反数将不会产生1。
但是,它显然有效,但是我不能证明这一点,因为对所有值进行强行测试将需要约140年的时间。
有什么建议吗?
我的测试:
assert(isPot(2.0)); //first solution fails here
assert(isPot(0.5));
assert(!isPot(5.0));
assert(!isPot(0.2));
2的幂是指一次存储在RAM中的值就是2的幂。因此所有尾数位均为0的数字。这是一个具有固有错误的解决方案,因为它假定以下值:
2.000000000000000000000000000000000000000000000000000000000000003
它将被转换为
2.0
并返回true,因为所有尾数位都为0,但最初不是2的幂。
最佳答案
您可以使用frexp作为可移植的方法将 double 数拆分为指数和尾数,然后检查尾数是否正好为0.5。
例子:
#include <math.h>
bool isPow2(double x)
{
int exponent = 0;
auto mantissa1 = frexp(x, &exponent);
return mantissa1 == 0.5;
}
BOOST_AUTO_TEST_CASE(powers_of_2)
{
std::vector<double> yes { 1, 2, 4, 8, 16, 0.5, 0.25, 65536 };
std::vector<double> no { 0, 3, 7, 15, 0.51, 0.24, 65535 };
for (size_t i = 0 ; i < yes.size() ; ++i) {
BOOST_CHECK_EQUAL(isPow2(yes[i]), true);
}
for (size_t i = 0 ; i < no.size() ; ++i) {
BOOST_CHECK_EQUAL(isPow2(no[i]), false);
}
}