我必须找到可以大到10 ^ 18的第n个数字根,其中n大到10 ^ 4。
我知道使用pow()我们可以使用
x = (long int)(1e-7 + pow(number, 1.0 / n))
但这对在线编程评委给出了错误的答案,但在我所采取的所有案例中,都给出了正确的结果。对于给定的约束,这种方法是否有问题 注意:此处的第n个根表示其n次幂小于或等于给定数字的最大整数,即x ^ n <=数字的最大“x”。 在答案之后,我知道这种方法是错误的,那么我应该怎样做呢?
答案 0 :(得分:3)
你可以使用
x = (long int)pow(number, 1.0 / n)
鉴于n
的价值很高,大多数答案都是1。
更新:
在OP评论之后,这种方法确实存在缺陷,因为在大多数情况下,1 / n没有精确的浮点表示,并且1 / n次幂的最低值可能会偏离1。
并且舍入不是更好的解决方案,它可以使一个超出一个根。
另一个问题是,高达10 ^ 18的值无法使用双精度精确表示,而64位整数则无法表示。
我的建议:
1)在(隐式)强制转换之前截断数字的11个低位比特,以避免FP单位向上舍入(不确定这是否有用)。
2)使用pow
函数得到第n个根的低估,让r
。
3)仅使用整数运算(通过重复平方)计算r+1
的n次幂。
4)如果第n次幂适合,解是r+1
而不是r
。
当计算1 / n时,FP单元可能会向上舍入,导致结果略微过大。我怀疑这个“太大”在最终结果中可能会达到一个单位,但是应该检查这个。
答案 1 :(得分:0)
我想我终于理解了你的问题。你想要做的就是将一个值(比如 X )提高到数字的倒数,比如说 n (即找到ⁿ√X̅),然后向下舍入。如果您然后提高 n 次幂的答案,它将永远不会大于原来的 X 。问题是计算机有时会遇到舍入错误。
#include <cmath>
long find_nth_root(double X, int n)
{
long nth_root = std::trunc(std::pow(X, 1.0 / n));
// because of rounding error, it's possible that nth_root + 1 is what we actually want; let's check
if (std::pow(nth_root + 1, n) <= X) {
return nth_root + 1;
}
return nth_root;
}
当然,最初的问题是找到满足等式X≤Yⁿ的最大整数 Y 。这很容易写:
long find_nth_root(double x, int d)
{
long i = 0;
for (; std::pow(i + 1, d) <= x; ++i) { }
return i;
}
这可能比你预期的要快。但是你可以用二进制搜索做得更好:
#include <cmath>
long find_nth_root(double x, int d)
{
long low = 0, high = 1;
while (std::pow(high, d) <= x) {
low = high;
high *= 2;
}
while (low != high - 1) {
long step = (high - low) / 2;
long candidate = low + step;
double value = std::pow(candidate, d);
if (value == x) {
return candidate;
}
if (value < x) {
low = candidate;
continue;
}
high = candidate;
}
return low;
}
答案 2 :(得分:0)
我使用我编写的例程。这是我在这里看到的最快的。它还可以处理多达64位。顺便说一句,n1是输入数字。
for (n3 = 0; ((mnk) < n1) ; n3+=0.015625, nmrk++) {
mk += 0.0073125;
dad += 0.00390625;
mnk = pow(n1, 1.0/(mk+n3+dad));
mnk = pow(mnk, (mk+n3+dad));
}
尽管并不总是完美的,但它确实是最接近的。