我需要找到一个最大的数字,x代表给定的y和n,这样x ^ y< = n
这里n可以是非常大的数 - 1 <= n <= 10 ^ 10 1&lt; = y&lt; = 10 ^ 5
for example :
for y = 5 and n = 1024
x ^ 5, then x = 4 (4 ^ 5 = 1024)
for y = 5 and n = 480
x ^ 5 , then x = 3 (3 ^ 5 = 243, 4 ^ 5 = 1024) - selecting lowest one, so x = 3
我写了一个小程序,但我想要更高效的技术,因为n和y可能非常大。
def get(y, n):
x = 1
while x ** y <= n:
x += 1
return x - 1
答案 0 :(得分:2)
使用多精度算术库,例如gmpy2的iroot
。
>>> import gmpy2
>>> root, exact = gmpy2.iroot(n, y)
这只是一个整数的第n个根算法。它应该是快速和正确的,即使对于大数字(在一般情况下浮动不能保证的东西)。
返回的第二个值是一个布尔值,表示根是否准确。
>>> print(*gmpy2.iroot(1024, 5))
4 True
>>> print(*gmpy2.iroot(480, 5))
3 False
答案 1 :(得分:0)
如果您应用浮动数学,则可以对整数使用二进制搜索从O(x)
移动到O(log(x))
:
x^y = n // ^(1/y)
x = n^1/y
x = floor(pow(n,1/y))
您的示例n=400
和y=5
是这样的:
x = floor(pow(400,1/5))
x = floor(pow(400,0.2))
x = floor(3.3144540173399868004685801443126)
x = 3
对于大n
,粗略的将不适用于基本浮动类型。在这种情况下,要么在大整数上使用bin搜索,要么在没有它的情况下使用你自己的bigint pow。无论如何,这两种方法都在这里描述:
<强> [EDIT1] 强>
在吸收你的意见之后:
n = < 1 , 10^10 >
y = < 1 , 10^5 >
no FPU just integer math
我会使用二进制搜索。您需要使用至少ceil(log2(10^10))=34 bit
个变量,因此无符号的64位QWORD
。如果你没有这样的变量,你需要首先从较低的位宽变量实现它。
二进制搜索掩码将是:
m = 2^33 = 1<<33 = 0x0000000200000000
因此,您首先需要实施pow
,然后root
调整来自链接答案的代码 C ++ 结果:
#define T_bits 34
#define T_MSB 0x0000000200000000
#define T QWORD
T pow(T x,T y) // power by squaring returns z=x^y where x>=0, y>=0
{
T i,z=1;
for (i=0;i<T_bits;i++) // test all bits from MSB to LSB
{
z*=z;
if (T(y&T_MSB)) z*=x;
y<<=1;
}
return z;
}
T bits(T x) // count how many bits is in x
{
T m=T_MSB,z=T_bits;
for (;m;m>>=1,z--)
if (x>=m) break;
return z;
}
T root(T x,T y) // bin search y-th root returns z=x^(1/y)
{
T m,z;
m=((bits(x)+y-1)/y); // ceil(bits(x)/y)
if (m) m=1<<m; else m=1; // MSB of the result for bin search 2^(ceil(bits(x)/y))
for (z=0;m;m>>=1) // test all bits of x from MSB to LSB
{
z|=m; // set actual bit
if (pow(z,y)>x) z^=m; // clear if result exceedes x
}
return z;
}
对于那些只有32位算术且有情人限制n<2^32
的人,将定义更改为:
#define T_bits 32
#define T_MSB 0x80000000
#define T DWORD
或使用您随意使用的任何其他变量类型。 T
是您的数据类型T_MSB
是MSB位设置,T_bits
是位数。
如果您使用:
root(400,5);
它将返回3
。您可以使用**
代替pow
我不能,因为我的编译器无法识别**
运算符。现在解释二进制搜索
让我们假设你的榜样。您从x=1
开始,然后测试x=2
然后x=3
,依此类推,直到您越过x^y>=n
,所以实际上您检查了pow(n,1/y)
个值。如果我们使用会导致n=10000, y=2
测试的100
。
二进制搜索不会增加,而是设置单个位。 10000
有14位,所以ceil(14/y)=7
所以过程将是:
x with set bit| x^y | action
-------------------------------
0100 0000 bin | 4096 | none
0110 0000 bin | 9216 | none
0111 0000 bin | 12544 | clear
0110 1000 bin | 10816 | clear
0110 0100 bin | 10000 | none
0110 0010 bin | 10404 | clear
0110 0001 bin | 10201 | clear
-------------------------------
0110 0000 bin | 10000 | result
仅导致7
次测试,而不是您的幼稚100
。