求平方根时获得精确答案(非近似)的最快算法

发布于 2024-10-18 02:34:53 字数 570 浏览 6 评论 0原文

抱歉标题不清楚,但我不知道如何正确表述(请随意编辑),所以我将给出示例:

sqrt(108) ~ 10.39...但我希望它像这样 sqrt(108) =6*sqrt(3) 所以这意味着扩展到两个数字

这就是我的算法

i = floor(sqrt(number))                  //just in case, floor returns lowest integer value :)
while (i > 0)                            //in given example number 108
  if (number mod (i*i) == 0)
    first = i                            //in given example first is 6
    second = number / (i*i)              //in given example second is 3
    i = 0
  i--

也许你知道更好的算法?

如果重要的话我会使用 PHP,当然我会使用适当的语法

Sorry for unclear title, but I don't know how to state it properly (feel free to edit), so I will give example:

sqrt(108) ~ 10.39... BUT I want it to be like this sqrt(108)=6*sqrt(3) so it means expanding into two numbers

So that's my algorithm

i = floor(sqrt(number))                  //just in case, floor returns lowest integer value :)
while (i > 0)                            //in given example number 108
  if (number mod (i*i) == 0)
    first = i                            //in given example first is 6
    second = number / (i*i)              //in given example second is 3
    i = 0
  i--

Maybe you know better algorithm?

If it matters I will use PHP and of course I will use appropriate syntax

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

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

发布评论

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

评论(3

能否归途做我良人 2024-10-25 02:34:53

对此没有快速算法。它要求您找到所有平方因子。这至少需要一些因式分解。

但你可以大大加快你的接近速度。首先,您只需要找到 n 的立方根以内的质因数,然后使用 确定整数的平方根是否是整数的最快方法

接下来加快速度,从底层开始工作。每次找到质因数时,重复将 n 除以它,累加平方。当你减少 n 的大小时,就会减少你将达到的限制。这可以让您利用大多数数字可以被一些小数字整除的事实,从而快速减少剩余要分解的数字的大小,并让您更快地停止搜索。

接下来的性能改进,开始变得更聪明地知道你用哪些数字来进行试除。例如特殊情况2,则只测试奇数。您刚刚再次将算法的速度提高了一倍。

但请注意,即使有了所有这些加速,您也只是获得了更高效的强力。它仍然是蛮力,并且仍然不会很快。 (尽管它通常比您当前的想法快得多。)

这里有一些伪代码可以清楚地说明这一点。

integer_sqrt = 1
remainder = 1

# First we special case 2.
while 0 == number % 4:
    integer_sqrt *= 2
    number /= 4

if 0 == number / 2:
    number /= 2
    remainder *= 2

# Now we run through the odd numbers up to the cube root.
# Note that beyond the cube root there is no way to factor this into
#    prime * prime * product_of_bigger_factors
limit = floor(cube_root(number + 1))
i = 3
while i <= limit:
    if 0 == number % i:
        while 0 == number % (i*i):
            integer_sqrt *= i
            number /= i*i
        if 0 == number % (i*i):
            number /= i
            remainder *= i
        limit = floor(cube_root(number + 1))
    i += 2

# And finally check whether we landed on the square of a prime.

possible_sqrt = floor(sqrt(number + 1))
if number == possible_sqrt * possible_sqrt:
    integer_sqrt *= possible_sqrt
else:
    remainder *= number

# And the answer is now integer_sqrt * sqrt(remainder)

请注意,各种+1是为了避免浮点数不精确的问题。

运行 2700 的算法的所有步骤,会发生以下情况:

number = 2700
integer_sqrt = 1
remainder = 1

enter while loop
    number is divisible by 4
        integer_sqrt *= 2 # now 2
        number /= 4 # now 675

    number is not divisible by 4
        exit while loop

number is not divisible by 2

limit = floor(cube_root(number + 1)) # now 8
i = 3
enter while loop
    i < =limit # 3 < 8
        enter while loop
            number is divisible by i*i # 9 divides 675
                integer_sqrt *= 3 # now 6
                number /= 9 # now 75

            number is not divisible by i*i # 9 does not divide 75
                exit while loop

        i divides number # 3 divides 75
            number /= 3 # now 25
            remainder *= 3 # now 3

        limit = floor(cube_root(number + 1)) # now 2

    i += 2 # now 5

    i is not <= limit # 5 > 2
        exit while loop

possible_sqrt = floor(sqrt(number + 1)) # 5

number == possible_sqrt * possible_sqrt # 25 = 5 * 5
    integer_sqrt *= possible_sqrt # now 30

# and now answer is integer_sqrt * sqrt(remainder) ie 30 * sqrt(3)

There is no fast algorithm for this. It requires you to find all the square factors. This requires at least some factorizing.

But you can speed up your approach by quite a bit. For a start, you only need to find prime factors up to the cube root of n, and then test whether n itself is a perfect square using the advice from Fastest way to determine if an integer's square root is an integer.

Next speed up, work from the bottom factors up. Every time you find a prime factor, divide n by it repeatedly, accumulating out the squares. As you reduce the size of n, reduce your limit that you'll go to. This lets you take advantage of the fact that most numbers will be divisible by some small numbers, which quickly reduces the size of the number you have left to factor, and lets you cut off your search sooner.

Next performance improvement, start to become smarter about which numbers you do trial divisions by. For instance special case 2, then only test odd numbers. You've just doubled the speed of your algorithm again.

But be aware that, even with all of these speedups, you're just getting more efficient brute force. It is still brute force, and still won't be fast. (Though it will generally be much, much faster than your current idea.)

Here is some pseudocode to make this clear.

integer_sqrt = 1
remainder = 1

# First we special case 2.
while 0 == number % 4:
    integer_sqrt *= 2
    number /= 4

if 0 == number / 2:
    number /= 2
    remainder *= 2

# Now we run through the odd numbers up to the cube root.
# Note that beyond the cube root there is no way to factor this into
#    prime * prime * product_of_bigger_factors
limit = floor(cube_root(number + 1))
i = 3
while i <= limit:
    if 0 == number % i:
        while 0 == number % (i*i):
            integer_sqrt *= i
            number /= i*i
        if 0 == number % (i*i):
            number /= i
            remainder *= i
        limit = floor(cube_root(number + 1))
    i += 2

# And finally check whether we landed on the square of a prime.

possible_sqrt = floor(sqrt(number + 1))
if number == possible_sqrt * possible_sqrt:
    integer_sqrt *= possible_sqrt
else:
    remainder *= number

# And the answer is now integer_sqrt * sqrt(remainder)

Note that the various +1s are to avoid problems with the imprecision of floating point numbers.

Running through all of the steps of the algorithm for 2700, here is what happens:

number = 2700
integer_sqrt = 1
remainder = 1

enter while loop
    number is divisible by 4
        integer_sqrt *= 2 # now 2
        number /= 4 # now 675

    number is not divisible by 4
        exit while loop

number is not divisible by 2

limit = floor(cube_root(number + 1)) # now 8
i = 3
enter while loop
    i < =limit # 3 < 8
        enter while loop
            number is divisible by i*i # 9 divides 675
                integer_sqrt *= 3 # now 6
                number /= 9 # now 75

            number is not divisible by i*i # 9 does not divide 75
                exit while loop

        i divides number # 3 divides 75
            number /= 3 # now 25
            remainder *= 3 # now 3

        limit = floor(cube_root(number + 1)) # now 2

    i += 2 # now 5

    i is not <= limit # 5 > 2
        exit while loop

possible_sqrt = floor(sqrt(number + 1)) # 5

number == possible_sqrt * possible_sqrt # 25 = 5 * 5
    integer_sqrt *= possible_sqrt # now 30

# and now answer is integer_sqrt * sqrt(remainder) ie 30 * sqrt(3)
腹黑女流氓 2024-10-25 02:34:53
  1. 按升序列出所有素因数,例如 2700 = 2*2*3*3*3*5*5。这是最慢的步骤,需要 sqrt(N) 运算。
  2. 创建一个累加器(从 1 开始)。扫描此列表。对于每对数字,将累加器乘以它们(其中之一)。所以扫描完上面的列表后,你会得到 2*3*5。
  3. 累加器是您的乘数。其余的仍保留在平方根下。
  1. List all prime divisors in increasing order e.g. 2700 = 2*2*3*3*3*5*5. This is the slowest step and requires sqrt(N) operations.
  2. Create an accumulator (start with 1). Scan this list. For every pair of numbers, multiply the accumulator by (one of) them. So after scanning the list above, you get 2*3*5.
  3. Accumulator is your multiplier. The rest remains under square root.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文