double precision - pow()

double precision - pow()

本文关键字:pow precision double      更新时间:2023-10-16

我想计算[n^(1/k)],其中nlong long2 <= k <= lg(n);k是整数。

我想也许我可以用这个:

long long d = pow(n,1.0/k)-1;
while(power(d,k) < n)
    d++;
d--;

但是它可能在最后一步溢出CCD_ 4。

如果我写:,是否保证d将是pow(n,1.0/k)四舍五入

long long d = long long(pow(n,1.0/k));

如果没有,什么是容易的&计算floor(pow(n,1.0/k)) 的安全方法

如果不确切了解stdlib中pow的实现,您就不能绝对确定

floor(pow(n,1.0/k)) or (long long)pow(n,1.0/k)

返回正确的结果。1.0/k引入了小的不准确性,并且加上pow的不准确度(由于doubles的表示而不可避免),如果nk次方或非常接近1,则pow()的结果可能刚好移动超过整数阈值。

使用Haskell的(**)的示例,它与math.h中的pow()做相同的事情,但它可能有不同的实现:

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))或通过重复平方求幂)。通过将rr+1分别提高到k-1次方,可以避免溢出(除非r为1,否则您可以在必要时通过测试k < 64 && n < (1ull << k)轻松处理这种特殊情况)。

当然,在floor(pow(n,1.0/k))以上的情况下,对特殊情况和修复的测试会花费时间,几乎所有情况下都不会做任何事情,所以这可能不值得。

您要求担保。不幸的是,对于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。ε的大小应该根据变量的精度和您使用的数字的大小来确定。

pow()返回一个双精度,我认为这就是您错过的