我想计算 [n ^(1 / k)] ,其中n
是long long
和2 <= k <= lg(n)
; k是整数。
我想我可以用这个:
long long d = pow(n,1.0/k)-1;
while(power(d,k) < n)
d++;
d--;
但最后一步可能会溢出long long
。
如果我写的话,是否保证d
将为pow(n,1.0 / k)向下舍入:
long long d = long long(pow(n,1.0/k));
如果没有,那么什么是简单的&amp;安全的方式来计算floor(pow(n,1.0/k))
答案 0 :(得分:1)
完全不知道stdlib中pow
的实现,你不能完全确定
floor(pow(n,1.0/k)) or (long long)pow(n,1.0/k)
返回正确的结果。 1.0/k
引入了一个小的不准确性,加上pow
的不准确性(由于double
s的表示而不可避免)可能只会将pow()
的结果移过整数阈值,如果n
是一个k
th 的力量,或者非常接近一个。
使用Haskell (**)
的示例,它与pow()
中的math.h
做同样的事情,但它可能有不同的实现:
Prelude> 3^37-1 :: Int
450283905890997362
Prelude> fromIntegral it ** (1.0/37)
3.0000000000000004
但它始终至少非常接近正确的结果,因此您可以将其用作快速修正的起点。
// assumes k > 2
long long r = (long long)pow(n,1.0/k);
while (n/power(r+1,k-k/2) >= power(r+1,k/2)) ++r;
while (n/power(r,k-k/2) < power(r,k/2)) --r;
其中power(a,b)
是整数幂函数(例如,可以是round(pow(a,b))
,或者通过重复平方来取幂)。通过将r
resp r+1
仅提升到k-1
th 次幂,可以避免溢出(除非r
为1,否则您可以处理如果有必要,可以通过测试k < 64 && n < (1ull << k)
)轻松完成这一特殊情况。
当然,特殊情况的测试和修正费用时间几乎在所有情况下都不会超过floor(pow(n,1.0/k))
,所以它可能不值得。
答案 1 :(得分:0)
你要求保证。不幸的是,对于C / C ++中的类型,几乎没有什么保证。虽然您会发现long long
通常是64位,但未定义这些数据类型的精确大小。但是,我相信1.0
默认为float
,通常为32位。 float pow(float base, float exponent)
和double pow(double base, double exponent)
都有,我不确定C ++会理解您要使用哪一个,除非您指定它。因此,转换时可能会失去精度。哦,顺便说一下,即使double
可能不如long long
精确,因为它也存储了指数。
另一个问题是浮点转换可能是不精确的,即使你认为它不应该是。我曾经遇到过这样的情况:我从stdin
读取一个浮点变量的整数,然后立即将其转换回int
,并发现它是从一个整数值向下舍入的到下面的一个!为避免这种情况,您应该在类型转换之前添加一个小epsilon。应根据变量的精确度和您正在使用的数字的大小来确定epsilon的大小。
答案 2 :(得分:-1)
pow()返回一个double,我认为这是你错过的