一系列整数是否至少包含一个完全平方数?

发布于 2024-09-07 15:23:57 字数 892 浏览 7 评论 0原文

给定两个整数 ab,是否有一种有效的方法来测试是否存在另一个整数 n 使得 a ≤  ;n2 < b?

我不需要知道n,只需要知道是否至少有一个这样的n存在,所以我希望避免计算任何的平方根区间内的数字。

虽然 测试单个整数是否是完美平方比计算平方根更快,范围可能很大,我也希望避免对范围内的每个数字执行此测试。

示例:

  • intervalContainsSquare(2, 3) => false
  • intervalContainsSquare(5, 9) =>; false(注意:9 在此区间之外)
  • intervalContainsSquare(9, 9) => false(此区间为空)
  • intervalContainsSquare(4, 9) =>; true(4 在此区间内)
  • intervalContainsSquare(5, 16) => true(9 在此区间内)
  • intervalContainsSquare(1, 10) => true(1、4、9 都在这个区间内)

Given two integers a and b, is there an efficient way to test whether there is another integer n such that a ≤ n2 < b?

I do not need to know n, only whether at least one such n exists or not, so I hope to avoid computing square roots of any numbers in the interval.

Although testing whether an individual integer is a perfect square is faster than computing the square root, the range may be large and I would also prefer to avoid performing this test for every number within the range.

Examples:

  • intervalContainsSquare(2, 3) => false
  • intervalContainsSquare(5, 9) => false (note: 9 is outside this interval)
  • intervalContainsSquare(9, 9) => false (this interval is empty)
  • intervalContainsSquare(4, 9) => true (4 is inside this interval)
  • intervalContainsSquare(5, 16) => true (9 is inside this interval)
  • intervalContainsSquare(1, 10) => true (1, 4 and 9 are all inside this interval)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

我家小可爱 2024-09-14 15:23:57

据我所知,计算一个数字是否是平方并不比在困难情况下计算其平方根快。事实是,您可以进行预先计算来知道它不是正方形,这平均可以节省您的时间。

同样,对于这个问题,您可以进行预计算以确定 sqrt(b)-sqrt(a) >= 1,这意味着 a 和 b 相距足够远,它们之间必须有一个正方形。对于某些代数,这种不等式相当于 (ba-1)^2 >= 4*a 的条件,或者如果您想要更对称的形式,则 (ab)^2+1 >= 2* (a+b)。因此,这一预计算不需要平方根,只需一个整数乘积和一些加法和减法即可完成。

如果 a 和 b 几乎完全相同,那么您仍然可以使用查看低位二进制数字作为预计算的技巧来知道它们之间不存在正方形。但它们必须非常接近,以至于这种预先计算可能不值得。

如果这些预计算没有结论,那么除了其他人的解决方案之外,我想不出任何其他解决方案,a <= ceil(sqrt(a))^2 < b.


由于存在正确进行代数的问题:

sqrt(b)-sqrt(a) >= 1
sqrt(b) >= 1+sqrt(a)
b >= 1+2*sqrt(a)+a
b-a-1 >= 2*sqrt(a)
(b-a-1)^2 >= 4*a

另外:通常当 a 是一个很大的数时,您可以使用牛顿法或使用查找表后跟几个牛顿法步骤来计算 sqrt(a)。原则上计算 ceil(sqrt(a)) 比 sqrt(a) 更快,因为浮点算术可以简化为整数算术,并且因为您不需要那么多牛顿法步骤来确定高精度你就会扔掉。但实际上,如果数值库函数使用以微代码实现的平方根,则速度会快得多。如果出于某种原因您没有该微代码来帮助您,那么手动编写 ceil(sqrt(a)) 可能是值得的。也许最有趣的情况是 a 和 b 是无界整数(例如一千位数字)。但对于普通的、未过时的计算机上的普通大小的整数,你无法击败 FPU。

Computing whether or not a number is a square isn't really faster than computing its square root in hard cases, as far as I know. What is true is that you can do a precomputation to know that it isn't a square, which might save you time on average.

Likewise for this problem, you can do a precomputation to determine that sqrt(b)-sqrt(a) >= 1, which then means that a and b are far enough apart that there must be a square between them. With some algebra, this inequality is equivalent to the condition that (b-a-1)^2 >= 4*a, or if you want it in a more symmetric form, that (a-b)^2+1 >= 2*(a+b). So this precomputation can be done with no square roots, only with one integer product and some additions and subtractions.

If a and b are almost exactly the same, then you can still use the trick of looking at low order binary digits as a precomputation to know that there isn't a square between them. But they have to be so close together that this precomputation might not be worth it.

If these precomputations are inconclusive, then I can't think of anything other than everyone else's solution, a <= ceil(sqrt(a))^2 < b.


Since there was a question of doing the algebra right:

sqrt(b)-sqrt(a) >= 1
sqrt(b) >= 1+sqrt(a)
b >= 1+2*sqrt(a)+a
b-a-1 >= 2*sqrt(a)
(b-a-1)^2 >= 4*a

Also: Generally when a is a large number, you would compute sqrt(a) with Newton's method, or with a lookup table followed by a few Newton's method steps. It is faster in principle to compute ceil(sqrt(a)) than sqrt(a), because the floating point arithmetic can be simplified to integer arithmetic, and because you don't need as many Newton's method steps to nail down high precision that you're just going to throw away. But in practice, a numerical library function can be much faster if it uses square roots implemented in microcode. If for whatever reason you don't have that microcode to help you, then it might be worth it to hand-code ceil(sqrt(a)). Maybe the most interesting case would be if a and b are unbounded integers (like, a thousand digits). But for ordinary-sized integers on an ordinary non-obsolete computer, you can't beat the FPU.

傾城如夢未必闌珊 2024-09-14 15:23:57

求较小数的平方根。如果这是一个整数那么你就完成了。
否则,将数字四舍五入并平方。如果小于 b 则为真。

这样您只需要计算一个平方根。

为了避免出现 a 等于 b 的问题,您应该先检查一下。因为这种情况总是假的。

Get the square root of the lower number. If this is an integer then you are done.
Otherwise round up and square the number. If this is less than b then it is true.

You only need to compute one square root this way.

In order to avoid a problem of when a is equal to b, you should check that first. As this case is always false.

浮萍、无处依 2024-09-14 15:23:57

如果您接受计算两个平方根,由于其单调性,您将得到这个不等式,它相当于您的起始不等式:

sqrt(a) <= n < sqrt(b)

因此,如果 floor(sqrt(a)) != Floor(sqrt(b)), floor(sqrt(b)) - 1 保证是这样的 n

If you will accept calculating two square roots, because of its monotonicity you have this inequality which is equivalent to your starting one:

sqrt(a) <= n < sqrt(b)

thus, if floor(sqrt(a)) != floor(sqrt(b)), floor(sqrt(b)) - 1 is guaranteed to be such an n.

听不够的曲调 2024-09-14 15:23:57
  1. 取较小数的平方根并向上取整
  2. 取较大数的平方根并向下取整
  3. 如果 1 小于或等于 2,则会有一个完美的平方
  1. get the square root of the lower number and round it up
  2. get the square root of the higher number and round it down
  3. if 1 is lower or equal 2, there will be a perfect square
掀纱窥君容 2024-09-14 15:23:57

求 sqrt(a) 和 sqrt(b) 的积分部分,即 sa 和 sb。

如果 sa2 = a,则输出 yes。

如果 sb2 = b 且 sa = sb-1,则输出 no。

如果sa< sb 输出是。

否则输出编号。

您可以优化上面的内容以摆脱 sqrt(b) 的计算(类似于 JDunkerly 的答案)。

或者您是否也想避免计算 a 和 b 的平方根?


使用类似于二分查找的方法可以完全避免计算平方根。

您首先猜测 n,n = 1 并计算 n2

考虑是否 a <= n < b、你可以停下来了。

如果 n <一个< b,你将你的猜测加倍。
如果 a < b< n,使其接近当前+先前猜测的平均值。

这将是 O(logb) 时间。

Find the integral part of sqrt(a) and sqrt(b), say sa and sb.

If sa2 = a, then output yes.

If sb2 = b and sa = sb-1, then output no.

If sa < sb output yes.

Else output no.

You can optimize the above to get rid of the computation of sqrt(b) (similar to JDunkerly's answer).

Or did you want to avoid computing square roots of a and b too?


You can avoid computing square roots completely by using a method similar to binary search.

You start with a guess for n, n = 1 and compute n2

Consider if a <= n < b, you can stop.

If n < a < b, you double your guess n.
if a < b < n, you make it close to average of current + previous guess.

This will be O(logb) time.

西瓜 2024-09-14 15:23:57

除了 JDunkerley 的不错的解决方案(+1)之外,可能还有一个可能的改进需要测试并使用 整数平方根 计算整数平方根

In addition to JDunkerley's nice solution (+1), there could be a possible improvement that needs to be tested and uses integer square roots to calculate integer square roots

酷炫老祖宗 2024-09-14 15:23:57

为什么你希望完全避免平方根?甚至在找到解决此问题的最有效方法之前,您就已经看到只需要 2 个平方根的方法。这是在 O(1) 时间内完成的,所以在我看来,你希望做出的任何改进都需要更多的时间来思考,而不是节省你的计算时间。我错了吗?

Why are you hoping to avoid square roots entirely? Even before you get to the most efficient way of solving this, you have seen methods that call for only 2 square roots. That's done in O(1) time, so it seems to me that any improvement you could hope to make would take more time to think about than it would EVER save you computing time. Am I wrong?

怎言笑 2024-09-14 15:23:57

一种方法是使用牛顿法求 b整数平方根代码>.然后您可以检查该数字是否在该范围内。我怀疑它比简单地调用平方根函数更快,但它肯定更有趣:

int main( int argc, char* argv[] )
{
    int a, b;
    double xk=0, xk1;
    int root;
    int iter=0;
    a = atoi( argv[1] );
    b = atoi( argv[2] );

    xk1 = b / 32 + 1;  // +1 to ensure > 0
    xk1 = b;
    while( fabs( xk1 - xk ) >= .5 ) {
        xk = xk1;
        xk1 = ( xk + b / xk ) / 2.;
        printf( "%d) xk = %f\n", ++iter, xk1 );
    }

    root = (int)xk1;

    // If b is a perfect square, then this finds that root, so it also
    // needs to check if (n-1)^2 falls in the range.
    // And this does a lot more multiplications than it needs
    if ( root*root >= a && root*root < b ||
         (root-1)*(root-1) >= a && (root-1)*(root-1) < b )
        printf( "Contains perfect square\n" );
    else
        printf( "Does not contain perfect square\n" );

    return 1;
}

One way is to use Newton's method to find the integer square root for b. Then you can check if that number falls in the range. I doubt that it is faster than simply calling the square root function, but it is certainly more interesting:

int main( int argc, char* argv[] )
{
    int a, b;
    double xk=0, xk1;
    int root;
    int iter=0;
    a = atoi( argv[1] );
    b = atoi( argv[2] );

    xk1 = b / 32 + 1;  // +1 to ensure > 0
    xk1 = b;
    while( fabs( xk1 - xk ) >= .5 ) {
        xk = xk1;
        xk1 = ( xk + b / xk ) / 2.;
        printf( "%d) xk = %f\n", ++iter, xk1 );
    }

    root = (int)xk1;

    // If b is a perfect square, then this finds that root, so it also
    // needs to check if (n-1)^2 falls in the range.
    // And this does a lot more multiplications than it needs
    if ( root*root >= a && root*root < b ||
         (root-1)*(root-1) >= a && (root-1)*(root-1) < b )
        printf( "Contains perfect square\n" );
    else
        printf( "Does not contain perfect square\n" );

    return 1;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文