Java 对于两个数字,如何测试一个是否是另一个的整数幂?
对于整数x、y和n,(仅给出x和y)测试xn=y?如果x=8,y=512,那么n=3,这是真的。但是如果x=8,y=500,n必须在2.98左右(不是整数),因此语句的计算结果为false。使用对数是做这个测试的最好方法吗 提供了一些解决方案:Java 对于两个数字,如何测试一个是否是另一个的整数幂?,java,algorithm,logarithm,exponent,Java,Algorithm,Logarithm,Exponent,对于整数x、y和n,(仅给出x和y)测试xn=y?如果x=8,y=512,那么n=3,这是真的。但是如果x=8,y=500,n必须在2.98左右(不是整数),因此语句的计算结果为false。使用对数是做这个测试的最好方法吗 提供了一些解决方案: int n=y;而(n
int n=y;而(n
while (x%y == 0) x = x / y
return x == 1
对数法(这是我的版本):
对数(y,x)=对数x y
哪种方法评估速度更快,尤其是对于大数字?如果不进行基准测试,只看发生了什么,这一种应该是最快的
int n = y; while(n < x) n *= y; return n == x;
这是一个除法和一个模(本质上是第二个除法),所以它做了两倍的功,但是它可以更早地退出循环,所以它可能会赢
return ((log(y, x) % 1) == 0)
这使用了本质上是邪恶的浮点运算(尽管浮点运算在现代CPU芯片中变得更好更快)。然而,当你需要知道它是完整的还是不完整的时候,你做测试的模块是偶数还是奇数。如果不进行基准测试,只看发生了什么,这个应该是最快的
int n = y; while(n < x) n *= y; return n == x;
这是一个除法和一个模(本质上是第二个除法),所以它做了两倍的功,但是它可以更早地退出循环,所以它可能会赢
return ((log(y, x) % 1) == 0)
这使用了本质上是邪恶的浮点运算(尽管浮点运算在现代CPU芯片中变得更好更快)。然而,当你需要知道它是完整的还是不完整的时候,你测试它的模数是偶数还是奇数。如果存在一个b和e,其中b^e=n,那么数字n是一个完美的幂。例如,216=6^3=2^3*3^3是一种完美的力量,但72=2^3*3^2不是。如果数字n是完美幂,则指数e必须小于log2n,因为如果e大于,则2^e将大于n。此外,只需要测试素数*e*s,因为如果数字是复合指数的完美幂,那么它也将是复合分量素数因子的完美幂;例如,2^15=32768=32^3=8^5是一个完美的立方根,也是一个完美的第五根
我在我的博客上有一个数字。如果存在一个b^e=n的b和e,那么n是一个完美的幂。例如,216=6^3=2^3*3^3是一种完美的力量,但72=2^3*3^2不是。如果数字n是完美幂,则指数e必须小于log2n,因为如果e大于,则2^e将大于n。此外,只需要测试素数*e*s,因为如果数字是复合指数的完美幂,那么它也将是复合分量素数因子的完美幂;例如,2^15=32768=32^3=8^5是一个完美的立方根,也是一个完美的第五根
我在我的博客上有一个测试。对于大量用户,日志可能会更快,但您应该对其进行基准测试。这将涉及到转换为双重和反向,这可能是一个问题 我认为这可能是一个更好的解决方案:
long y = 512;
long x = 8;
if (x <= 1) return false;
while (y>1) {
// Find maximum x^(2^n) <= y
long xp = x; // x to some maximum power
long xp2; // experimental value of xp
while ((xp2 = xp*xp) <= y)
xp = xp2;
if (y%xp != 0) return false; // reject
y /= xp;
}
return y == 1;
长y=512;
长x=8;
if(x1){
//查找最大x^(2^n)对于较大的数字,日志可能会更快,但您应该对其进行基准测试。这将涉及到转换为double和back,这可能是一个问题
我认为这可能是一个更好的解决方案:
long y = 512;
long x = 8;
if (x <= 1) return false;
while (y>1) {
// Find maximum x^(2^n) <= y
long xp = x; // x to some maximum power
long xp2; // experimental value of xp
while ((xp2 = xp*xp) <= y)
xp = xp2;
if (y%xp != 0) return false; // reject
y /= xp;
}
return y == 1;
长y=512;
长x=8;
if(x1){
//查找最大值x^(2^n)对数方法需要更加小心,因为由于使用浮点近似,对数函数有少量不精确性。例如310=59049,但是:
log(59049, 3)
===> 9.999999999999998
是否可以对此进行补偿(通过检查答案是否与最接近的整数“足够接近”)取决于x和y的范围。如果y小于232,则我认为对数与整数成比例的最接近值(真实答案不是整数)是:
因此,选择一个比这个小的ε,您可以放心地使用对数方法:
n = log(y, x);
e = round(n);
if (abs(1 - n / e) < epsilon) {
/* y == x to the power of e */
} else {
/* y not a power of x */
}
因此,对于足够大的y,您不能依赖于对数:您需要在检查之后显式执行幂运算。对数方法需要更加小心,因为由于使用浮点近似,对数函数有少量的不精确性。例如310=59049,但是:
log(59049, 3)
===> 9.999999999999998
是否可以对此进行补偿(通过检查答案是否与最接近的整数“足够接近”)取决于x和y的范围。如果y小于232,则我认为对数与整数成比例的最接近值(真实答案不是整数)是:
因此,选择一个比这个小的ε,您可以放心地使用对数方法:
n = log(y, x);
e = round(n);
if (abs(1 - n / e) < epsilon) {
/* y == x to the power of e */
} else {
/* y not a power of x */
}
因此,对于足够大的y,您不能依赖对数:您需要在检查之后显式地执行求幂运算。对于合理的小输入,我相当确定您的第三种方法将工作得最好。(不过,您需要更加小心地检查完整性。)
值得思考的是:
您可以非常快速地计算x
的幂,即sqrt(y)
的幂(即O(M(logy))时间),然后根据该幂(O(M(logy)logy)时间)进行mod,以得到大小为一半的两个子问题
你可以使用相当差的对数近似值来获得n
上相当严格的界限。如果我知道一个整数在log_x(y)
的常数范围内,那么我只需要检查x
的常数次幂。这些检查使用“平方和乘法技术”完成得最快爱德华·福克的回答就是例证
即使在n
上有一个相当宽的范围,你也可以使用算术模对一个中等大小的随机素数进行运算,以大大缩小候选n
的范围。应该可以使用算术模对几个中等大小的随机素数进行运算,并结合中国剩余定理来缩小可能的