【问题标题】:Algorithm to find the largest square number smaller than n找到小于 n 的最大平方数的算法
【发布时间】:2015-02-07 18:03:01
【问题描述】:

如何有效地找到小于给定 int n 的最大平方数(即 4、9、16)?我有以下尝试:

int square = (int)Math.sqrt(number);
return square*square;

但它显然效率低下,只是为了让我们可以平方它而求平方根。

【问题讨论】:

  • en.wikipedia.org/wiki/Square_number 可能会有所帮助
  • @hatchet 不,关键是我想要它的整数部分。我想直接去平方数。
  • 需要 s/小于 n/不大于 n/g 以使您的代码正确。
  • @Deduplicator 看起来很粗略,但是 int->double 转换是准确的,而且 Math.sqrt 保证被正确四舍五入,所以可以做错误分析表明我们从来没有正确四舍五入 up 到一个整数(这是截断可能出错的唯一方法)。

标签: java algorithm math square-root


【解决方案1】:

预先说明:应该注意的是,能够将 sqrt 作为机器指令执行的处理器将足够快。毫无疑问,它的(微)程序使用的是Newton-Raphson,并且该算法具有二次收敛性,每次迭代的准确位数增加一倍。

因此,像这样的想法并不值得追求,尽管它们使用了很好的正方形属性等。(请参阅下一个建议)

// compute the root of the biggests square that is a power of two < n
public static int pcomp( int n ){
  long p2 = 1;
  int i = 0;
  while( p2 < n ){
    p2 <<= 2;
    i += 2;
  }
  p2 >>= 2;
  i -= 2;
  return (int)(p2 >>= i/2);
}

public static int squareLowerThan( int n ){
  int p = pcomp(n);
  int p2 = p*p;     // biggest power of two that is a square < n 
  int d = 1;        // increase using odd numbers until n is exceeded
  while( p2 + 2*p + d < n ){
    p2 += 2*p + d;
    d += 2;
  }
  return p2;
}

但我确信牛顿算法更快。二次收敛,记住。

public static int sqrt( int n ){
  int x = n;
  while( true ){
    int y = (x + n/x)/2;
    if( y >= x ) return x;
    x = y;
  }
}

这将返回整数平方根。返回 x*x 得到 n 下面的正方形。

【讨论】:

  • 这会比平方根的本机实现更快吗?
  • @AndyTurner 使用双倍?使用具有 sqrt 作为指令或其他拐杖的处理器?也许是也许不是。 :) - 但是,整数运算更快,所有其他条件都相同。
  • @laune:基准测试或者这只是一个轶事。整数运算使用更少的门,但如果你有足够的芯片空间,它本质上并不是更快。事实上,在现代处理器上,浮点除法可能比整数除法更快。
  • @rici 不过,“整数算术”一词不应该被理解为原始 CPU 指令时序:浮点数值算法往往需要更多代码,例如,用于决定何时停止迭代,或用于与字符串的转换。此外,某些优化只能在整数算术中完成,例如 i/2 与 f/2.0,或 i++ 与 f+1.0。更短的代码,更少的缓存行......但是当(如这里)单个 FP 指令完成大部分工作时,所有替代方案都可以放在一边。
【解决方案2】:

线性时间算法:

int largestSquare(int n) {
  int i = 0;
  while ((i+1)*(i+1) < n) {
    ++i;
  }
  return i*i;
}

【讨论】:

  • 如果这比求平方根还快,我会感到非常惊讶。
  • 我也是。但是你说你不想使用平方根。不使用平方根感觉就像是一种微优化。
  • 绝对是微优化。这就是我所要求的。这根本不是优化
  • 你想优化什么?例如结果的查找表在时间方面非常有效,但存储起来很糟糕。
【解决方案3】:

有一个牛顿算法来求平方根,你需要的是 m^2 而不是 m,在给定的链接中

https://math.stackexchange.com/questions/34235/algorithm-for-computing-square-root-of-a-perfect-square-integer

即使你想直接找平方而不是找m,我觉得也不会比这个快。

这里是工作代码

public static int squareLessThanN(int N)
{
        int x=N;
        int y=(x+N/x)/2;
        while(y<x)
        {
               x=y;
               y=(x+N/x)/2;
        }
        return x*x;
 }

但无论如何,似乎内置的平方根似乎更快。刚刚测量了两者的运行时间。

class Square{
        public static void main(String[] args)
        {
                long startTime = System.currentTimeMillis();
                System.out.println(squareLessThanN(149899437943L));
                long endTime   = System.currentTimeMillis();
                long totalTime = endTime - startTime;
                System.out.println("Running time is "+totalTime);

                startTime = System.currentTimeMillis();
                System.out.println(normal(149899437943L));
                endTime   = System.currentTimeMillis();
                totalTime = endTime - startTime;
                System.out.println("Running time is "+totalTime);

        }
        public static long squareLessThanN(long N)
        {
                long x=N;
                long y=(x+N/x)/2;
                while(y<x)
                {
                        x=y;
                        y=(x+N/x)/2;
                }
                return x*x;
        }
        public static long normal(long N)
        {
                long square = (long)Math.sqrt(N);
                return square*square;
        }
}

输出是

149899060224
Running time is 1
149899060224
Running time is 0

【讨论】:

    猜你喜欢
    • 2021-06-09
    • 2012-01-06
    • 2011-12-27
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多