3

I have to find a solution to the equation x2 + y2 = m where m can be any natural number and x,y are integers. This can be done in O(m1/2) by using brute force easily. Is there a way I can do this in constant time?

Sujay_K
  • 155
  • 1
  • 2
  • 10

1 Answers1

4

I'm not sure you can do it any better than O(sqrt(m)) for an arbitrary m but that's pretty damn good , much better than linear time :-)

The approach is to start x and y at opposite ends of the solution space and either increment the low end or decrement the high end, depending on whether the result is too low or too high (obviously if the result is perfect, return the values):

def solveForM(m):
    set lo to 0
    set hi to sqrt(m), rounded up.
    while lo < hi:
        testVal = lo * lo + hi * hi
        if testVal == m:
            return (lo, hi)
        if testVal > m:
            hi = hi - 1
        else lo = lo + 1
    return "No solution"

If m can be limited somehow, you could achieve O(1) by use of a lookup table (many optimisations come down to trading space for time), such as:

 0 ->  0, 0
 1 ->  0, 1
 2 ->  1, 1
       No solution for 3
 4 ->  0, 2
 5 ->  1, 2
       No solution for 6, 7
 8 ->  2, 2
 9 ->  0, 3
10 ->  1, 3
       No solution for 11, 12
13 ->  2, 3
... and so on.

A table like this can be generated with a small program along the lines of (Python 3):

for hi in range(1001):
    for lo in range(1001):
        m = lo * lo + hi * hi
        print("%5d -> %d, %d"%(m, lo, hi))

You have to sort (and possibly remove duplicates) afterwards to create a fast look-up table but the performance is okay with the generation of an unsorted list taking fifteen seconds for all m up to two million.

In any case, this is only run once, after which you would place the table into code where the time expense is incurred at compile time.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • m can be as large as 10^10 – Sujay_K Jan 17 '17 at 08:38
  • 1
    You can definitely do better: for prime `m`, there's an algorithm based on Fermat's descent method that will give a solution in polynomial time in `log(m)`. And for non-prime `m`, it's possible to build all solutions from the solutions for prime `m`. So for large composite `m`, the bottleneck essentially comes down to the time to factorise `m`. For a Python solution for prime inputs, see http://math.stackexchange.com/a/5883/117283 – Mark Dickinson Jan 17 '17 at 08:41
  • @MBo `set hi to sqrt(m), rounded up` is possibly the problem I am using `hi=sqrt(m)+1` which is fine – Spektre Jan 17 '17 at 12:33
  • @MBo, assuming you meant in the lookup table (where that exact text is), it's not so much a rounding error as it is faulty manual calculations on my part. I probably should have created the table with some code rather than relying on faulty wetware :-) Fixed now. – paxdiablo Jan 17 '17 at 23:32