Алгоритм целочисленных решений круга? - PullRequest
2 голосов
/ 17 октября 2019

Я пытаюсь найти целочисленные решения уравнения:

y^2 + x^2 = 2n^2

Если я найду это в альфа-вольфраме, все они будут найдены почти сразу, даже для очень большого n. Когда я реализовал метод грубой силы, он был очень медленным:

def psearch(n, count):
    for x in range(0, n):
        for y in range(0, n):
            if x*x + y*y == 2*n**2:
                print(x,y)
                count += 1
    return count

Так что я предполагаю, что есть гораздо более быстрый способ получить все целочисленные решения уравнения выше. Как я могу сделать это в python, чтобы у него было намного меньшее время выполнения?

Примечание: я видел этот вопрос , однако речь идет о поиске точек решетки в пределах aобведите не целочисленные решения уравнения круга. Также меня интересует поиск конкретных решений , а не только количество решений .

Редактировать: Я все еще ищу что-то на порядок быстрее. Вот пример: n = 5 должно иметь 12 целочисленных решений, чтобы найти то, что это должно быть, искать это уравнение на Wolfram alpha .

Редактировать 2: @victor zen дал феноменальный ответ на проблему. Кто-нибудь может придумать способ дальнейшей оптимизации своего решения?

Ответы [ 3 ]

6 голосов
/ 17 октября 2019

В вашем алгоритме вы ищете все возможные значения y. Это не нужно. Хитрость заключается в том, чтобы понять, что

y^2 + x^2 = 2n^2

прямо подразумевает, что

y^2 = 2n^2-x^2

, а это означает, что вам нужно только проверить, что 2n ^ 2-x ^ 2 - идеальный квадрат. Вы можете сделать это с помощью

y2 = 2*n*n - x*x 
#check for perfect square
y = math.sqrt(y2)
if int(y + 0.5) ** 2 == y2:
    #We have a perfect square.

Кроме того, в вашем алгоритме вы проверяете только значения x до n. Это неверноТак как y ^ 2 всегда будет положительным или нулевым, мы можем определить самое высокое значение x, которое мы должны проверить, установив y ^ 2 в его самое низкое значение (то есть 0). Следовательно, нам необходимо проверить все целочисленные значения x, удовлетворяющие

x^2 <= 2n^2

, что приводит к уменьшению до

abs(x) <= sqrt(2)*n.

. Объедините это с оптимизацией проверки только верхнего квадранта, и вы получите оптимизированный псевдонимиз

def psearch(n):
    count = 0
    top = math.ceil(math.sqrt(2*n*n))
    for x in range(1, top):
        y2 = 2*n*n - x*x 
        #check for perfect square
        y = math.sqrt(y2)
        if int(y + 0.5) ** 2 == y2:
            count+=4
    return count
3 голосов
/ 17 октября 2019

Достаточно выполнить поиск внутри первого октанта y>0, x<y (четыре решения (±n, ±n) очевидны и по симметрии решение (x, y) дает 8 копий (±x, ±y), (±y, ±x)).

По монотонности для данного y существует не более одного x. Вы можете найти его, следуя по дуге окружности постепенно, уменьшая y, затем настраивая x. Если вы строго соблюдаете условие x²+y²≤2n², вы получите приведенный ниже код, оптимизированный для использования только элементарной целочисленной арифметики (для эффективности вместо 10101 * используется 2x).

    x, y, d= 2 * n, 2 * n, 0
    while y > 0:
        y, d= y - 2, d - y + 1
        if d < 0:
            x, d= x + 2, d + x + 1
        if d == 0:
            print(x >> 1, '² + ', y >> 1, '² = 2.', n, '²', sep='')

Вот все решения для n между 1 и 100:

7² + 1² = 2.5²
14² + 2² = 2.10²
17² + 7² = 2.13²
21² + 3² = 2.15²
23² + 7² = 2.17²
28² + 4² = 2.20²
31² + 17² = 2.25²
35² + 5² = 2.25²
34² + 14² = 2.26²
41² + 1² = 2.29²
42² + 6² = 2.30²
46² + 14² = 2.34²
49² + 7² = 2.35²
47² + 23² = 2.37²
51² + 21² = 2.39²
56² + 8² = 2.40²
49² + 31² = 2.41²
63² + 9² = 2.45²
62² + 34² = 2.50²
70² + 10² = 2.50²
69² + 21² = 2.51²
68² + 28² = 2.52²
73² + 17² = 2.53²
77² + 11² = 2.55²
82² + 2² = 2.58²
84² + 12² = 2.60²
71² + 49² = 2.61²
79² + 47² = 2.65²
85² + 35² = 2.65²
89² + 23² = 2.65²
91² + 13² = 2.65²
92² + 28² = 2.68²
98² + 14² = 2.70²
103² + 7² = 2.73²
94² + 46² = 2.74²
93² + 51² = 2.75²
105² + 15² = 2.75²
102² + 42² = 2.78²
112² + 16² = 2.80²
98² + 62² = 2.82²
97² + 71² = 2.85²
113² + 41² = 2.85²
115² + 35² = 2.85²
119² + 17² = 2.85²
123² + 3² = 2.87²
119² + 41² = 2.89²
126² + 18² = 2.90²
119² + 49² = 2.91²
133² + 19² = 2.95²
137² + 7² = 2.97²
124² + 68² = 2.100²
140² + 20² = 2.100²
1 голос
/ 17 октября 2019

Вы можете оптимизировать этот алгоритм, возможно, рассматривая только один квадрант и умножая на 4.

import math
def psearch(n, count):
  for x in range( 0 , 2*n  + 1):
    ysquare = 2*(n**2) - x * x
    if (ysquare <0):
      break
    y = int(math.sqrt(ysquare))

    if ysquare ==  y * y :
      print(x,y)
      count+=1

  return count


print(psearch(13241324,0) * 4)

ВЫХОД

(1269716, 18682964)
(1643084, 18653836)
(11027596, 15134644)
(12973876, 13503476)
(13241324, 13241324)
(13503476, 12973876)
(15134644, 11027596)
(18653836, 1643084)
(18682964, 1269716)
36
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...