如何判断一个数时幂数?

这个来自于csdn的一篇文章,我总结了下,就写了这个java程序

 

public class PowerExponent {
 
 
int currentGreatestCommonDivisor = 0;//记录计算时当前质因子个数 之间的最大的公约数初始化为0表示不可用
 int currentPrimerDivisorCount =0 ; //用于记录当前质因素 个数计数
 int prePrimerDivisorCount =0;//前一个质因数计数个数
 int currentPrimerDivisor =0;         //先前质因子  
 public void setCurrentGreatestCommonDivisor(int value)
 
{
  
this.currentGreatestCommonDivisor = value;
 }

 
public int getCurrentGreatestCommonDivisor()
 
{
  
return this.currentGreatestCommonDivisor ;
 }

 
public boolean isPowerExponentNumber(final int orignNumber)
 
{
  
int number =orignNumber;
  prePrimerDivisorCount 
=0;
  currentPrimerDivisor 
=0;
  currentGreatestCommonDivisor 
= 0;//初始化为0表示不可用
  currentPrimerDivisorCount = 0;
  
if(number>3)
  
{
   
   currentPrimerDivisor 
= 2;
   
while(number%2 == 0)
   
{
    number 
/= 2;
    
++currentPrimerDivisorCount;
   }

   
int i = 3;
   
while(number >=i )
   
{
    
while(number%== 0)
    
{
     
if(i == currentPrimerDivisor)
     
{
      
++currentPrimerDivisorCount;
     }

     
else
     
{
      
//新的质因素开始,计数个数设置为1 ,统计前一个质数的个数,记录当前质因子
      prePrimerDivisorCount = currentPrimerDivisorCount;
      currentPrimerDivisor 
= i;
      currentPrimerDivisorCount 
= 1;
      
      
//判断最大公约数
      if(currentGreatestCommonDivisor != 0)
      
{
       
//如果最大公约数!=0表明一定不是第一次求最大公约数
       currentGreatestCommonDivisor = PowerExponent.FindGreatestCommonDivisor(currentGreatestCommonDivisor,prePrimerDivisorCount);
       
if(currentGreatestCommonDivisor == 1)
       
{
        
return false;
       }

      }

      
else
      
{
       currentGreatestCommonDivisor 
= prePrimerDivisorCount;
       
if(currentGreatestCommonDivisor == 1)
       
{
        
return false;
       }

      }

     }

     number 
/=i; 
    }

    
if(i*>orignNumber)
    
{
     
//存在一个比它开方还大的质因子所以必非幂数
     return false;
    }

    i
+=2;
   }

   
   
//质因素分解结束 number == 1
   if(currentGreatestCommonDivisor == 0 && currentPrimerDivisorCount >1 )
   
{
    
//只有一个质因子
    return true;
   }

   
else
   
{
    
//求所有质因子个数的 最大公约数
    currentGreatestCommonDivisor = PowerExponent.FindGreatestCommonDivisor(currentGreatestCommonDivisor,currentPrimerDivisorCount);
    
if(currentGreatestCommonDivisor == 1)
    
{
     
return false;
    }

    
else return true;
   }

  }

  
return  false;
 }

 
/**
  * 
  * 
@param a a>0
  * 
@param b b>0
  * 
@return 最大质因素
  
*/

 
public static int FindGreatestCommonDivisor(final int orignNumber_a,final int orignNumber_b)
 
{
  
int  a= orignNumber_a;
  
int  b= orignNumber_b;
  
if(a==1 || b== 1return 1;//互质
  
  
if( a%== 0 )
  
{
   
return b;
  }

  
if(b%== 0)
  
{
   
return a;
  }

  
int product =1 ;
  
int greatesCommonDivisor = 1;
  
  
while(a%2 == 0&& b%2 ==0)
  
{
   a 
/= 2;
   b 
/=2;
   product 
*=2;
  }

  
int i = 3;
  
while(a>=i&&b>=i)
  
{
   
while(a%== 0 && b%==0)
   
{
    a 
/= i;
    b 
/= i;
    product 
*=i;
   }

   
if(i * i > orignNumber_a || i*> orignNumber_b)
   
{
    
//当前的a ,b存在一个比它开方还大的质因子所以没有必要再分解质因子
    greatesCommonDivisor = product;
    
return greatesCommonDivisor;
   }

   i 
+= 2;
  }

  greatesCommonDivisor 
= product;
  
return greatesCommonDivisor;
 }

 
public static void main(String[] args) {
  
// TODO Auto-generated method stub
  PowerExponent pe = new PowerExponent();
  
boolean bRet = false;
  
long startMills = System.currentTimeMillis();
  
for(int i=1;i<64000;i++)
  
{
   bRet 
= pe.isPowerExponentNumber(i);
   
//System.out.println(i+"是幂指数吗?"+bRet);
   if(bRet)
   
{
    System.out.println(i
+"是幂指数");
   }

  }

  bRet 
= pe.isPowerExponentNumber(2147395600);
 
  
if(bRet)
  
{
   System.out.println(
2147395600+"是幂指数");
  }

  
  bRet 
= pe.isPowerExponentNumber(2*2*2*2*3*3*3*3*3*3*5*5*5*5);
  System.out.println(
2*2*2*2*3*3*3*3*3*3*5*5*5*5+"=2*2*2*2*3*3*3*3*3*3*5*5*5*5*7*7"+"是幂指数吗"+bRet);
  
long endMills = System.currentTimeMillis();
  System.out.println(
"耗时"+(endMills - startMills));
  
//System.out.println(PowerExponent.FindGreatestCommonDivisor(2*2*2*3*3*3*7*7*11*13,2*2*2*3*3*5*7*13));
 }

}

 

我的思路也在那篇文章中写过就是

所有质因数的个数构成的集合A{a1,a2,。。。}
而集合A中元素a1,a2,a3最大公约数s
如果s>1,那么N就是幂数。
比如果
2*2*2*2*3*3*3*3*3*3*3 质因数个数的集合{4,6}最大公约数为2〉1所以是幂数
5*5*5                  质因数个数的集合{3}最大公约数为3>1所以是幂数

因为质因数个数的最大公约数为s
那么队以任意质因数 pi,它出现的次数为ai;
必有ai %s = 0,所以一定能够将该质因数pi 分成s组,每组ai/s个。他的积为pi^(ai/s)

这样就将将所有质因数都分成了s组
原数N= {pi^(ai/s)} ^s,所以幂指数为s,底数为 pi^(ai/s)之积  注 i=1,2,3,..

 

判断一个是否是 **2 的**(即形如 \(2^n\),如 1, 2, 4, 8, 16...)可以通过以下位运算方法高效实现: --- ### **核心原理** 一个是 2 的,当且仅当它的二进制表示中 **有且仅有 1 个 `1`**,且该 `1` 出现在最高位。例如: - \(2^3 = 8\) → `0b1000` - \(2^5 = 32\) → `0b100000` --- ### **方法1:利用 `num & (num - 1)`** ```c bool is_power_of_two(unsigned int num) { return num != 0 && (num & (num - 1)) == 0; } ``` - **原理**: - 如果 `num` 是 2 的,则 `num - 1` 的二进制是全 `1`(如 `8 & 7 = 0b1000 & 0b0111 = 0`)。 - 需要额外检查 `num != 0`,因为 `0 & (-1)` 也满足 `0`,但 `0` 不是 2 的。 - **示例**: ```c is_power_of_two(8); // true (0b1000 & 0b0111 = 0) is_power_of_two(10); // false (0b1010 & 0b1001 = 0b1000 ≠ 0) ``` --- ### **方法2:利用补码性质(仅适用于无符号)** ```c bool is_power_of_two(unsigned int num) { return num != 0 && (num & -num) == num; } ``` - **原理**: - `-num` 是 `num` 的补码(按位取反后加 1),如果 `num` 是 2 的,则 `num & -num` 会保留唯一的 `1`(如 `8 & -8 = 0b1000 & 0b1000 = 8`)。 - **性能**:与方法 1 类似,但依赖补码运算。 --- ### **方法3:直接统计 `1` 的个** ```c bool is_power_of_two(unsigned int num) { return __builtin_popcount(num) == 1; // GCC/Clang 内置函 } ``` - **优点**:代码简洁,但需编译器支持。 - **缺点**:性能略低于方法 1 和方法 2(需遍历所有位)。 --- ### **边界情况处理** - **排除 `0`**:`0` 不是 2 的,需显式检查。 - **负(有符号)**:若输入为有符号(如 `int`),需先转换为无符号判断,避免补码干扰。 --- ### **代码示例(完整)** ```c #include <stdbool.h> #include <stdio.h> bool is_power_of_two(unsigned int num) { return num != 0 && (num & (num - 1)) == 0; } int main() { unsigned int nums[] = {0, 1, 2, 4, 5, 8, 10, 16}; for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { printf("%u: %s\n", nums[i], is_power_of_two(nums[i]) ? "true" : "false"); } return 0; } ``` **输出**: ``` 0: false 1: true 2: true 4: true 5: false 8: true 10: false 16: true ``` --- ### **应用场景** - 内存对齐检查(如 `malloc` 的块大小)。 - 哈希表扩容条件判断。 - 位图(Bitmap)操作优化。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值