5
\$\begingroup\$

I wrote a program in Python and in Java to search for the smallest integer solution of the equation:

$$a^5+b^5+c^5+d^5=e^5$$

(expected output is \133ドル^5 + 110^5 + 84^5 + 27^5 = 144^5\$)

Powers and roots are either computed directly ("direct calculation" method) or computed and stored in an array ("power lookup" method). Fifth powers are looked up like n5 = fifth_power[n]. Fifth power root is computed using a binary search in array 'fifth_power`.

I am running it on NetBeans if it matters. It takes:

  • 30 s (Python, direct)
  • 20 s (Python, lookup)
  • 5.6 s (Java, direct)
  • 0.8 s (Java, lookup)

Is there a way to boost Python performance? I am not looking for better math (sieving of some kind). I am looking for better implementation of "for each combination of a,b,c,d compute some of their powers, check if the sum is a perfect power. If it is - print the result".

Is it expected that Python runs some 20 times slower than Java?

Python 3.5

from array import *
import math
import time
#PYTHON, BRUTEFORCE : ~30 s
millis1 = int(round(time.time() * 1000))
keep_searching = True
a=1
result=""
while(keep_searching):
 a+=1
 for b in range(1,a+1):
 for c in range(1,b+1):
 for d in range(1,c+1):
 sum=math.pow(a,5)+math.pow(b,5)+math.pow(c,5)+math.pow(d,5)
 root = math.pow(sum,0.2)
 e = round(root)
 e5 = math.pow(e,5) 
 if(e5==sum):
 result="{}^5 + {}^5 + {}^5 + {}^5 = {}^5".format(int(a),int(b), int(c),int(d), int(e))
 keep_searching = False
 millis2 = int(round(time.time() * 1000))
print(result)
print("Found solution in {} ms".format(millis2-millis1))
#PYTHON, PRECOMPUTE POWERS: ~20 s
millis3 = int(round(time.time() * 1000)) 
#fifth_power #175 is enough
size=176
fifth_power = [None] * size
for i in range(size):
 fifth_power[i]=long(math.pow(i,5))
millis4 = int(round(time.time() * 1000)) 
#returns value if it is a perfect power (32 returns 2) 
#returns -1 if between perfect powers, -2 if greater than max value in array, -3 if smaller than min value in array
def check_perfect_power(number, min, max, fifth_power):
 current=int((min+max)/2)
 while(max>=min):
 if(number==fifth_power[current]):
 return current
 elif(number>fifth_power[current]):
 min=current+1
 current=int((max+min)/2)
 else:
 max=current-1
 current=int((max+min)/2)
 if(min>=len(fifth_power)): 
 return -2
 if(max<0):
 return -3
 return -1 
keep_searching = True
a=0
result=""
while(keep_searching):
 a+=1
 for b in range(1,a+1):
 for c in range(1,b+1):
 for d in range(1,c+1):
 mymax=min(int(a*1.32)+1, size-1)
 e=check_perfect_power(fifth_power[a]+fifth_power[b]+fifth_power[c]+fifth_power[d], a, mymax, fifth_power)
 if(e>0):
 result="{}^5 + {}^5 + {}^5 + {}^5 = {}^5".format(int(a),int(b), int(c),int(d), int(e))
 keep_searching = False
 millis5 = int(round(time.time() * 1000))
print(result)
print("Populated in {} ms, find solution in {} ms".format(millis4-millis3,millis5-millis4))
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Sep 12, 2016 at 18:31
\$\endgroup\$
5
  • \$\begingroup\$ Obvious question: Did you implement it in the same way for both Java and Python? \$\endgroup\$ Commented Sep 12, 2016 at 21:00
  • \$\begingroup\$ I did. pastebin.com/G4V3fHnD So, is this performance difference expected? \$\endgroup\$ Commented Sep 12, 2016 at 21:12
  • \$\begingroup\$ stackoverflow.com/questions/672857/is-python-slower-than-java-c & snaplogic.com/blog/… \$\endgroup\$ Commented Sep 13, 2016 at 7:23
  • \$\begingroup\$ On my machine for bruteforce approach: Py: 58s Rust 1.7s C++: 1.3s F# 2.4s. My recommendation: if you do a lot of numerics, don't use python. \$\endgroup\$ Commented Sep 13, 2016 at 23:23
  • 1
    \$\begingroup\$ ... And haskell: 1.7s \$\endgroup\$ Commented Sep 14, 2016 at 1:30

2 Answers 2

1
\$\begingroup\$

An obvious possible improvement for both languages is storing the values to the fifth power (But I'm going to focus on python here).

In python, while is a keyword and does not need parenthesis. Also, global lookup of methods is slower than local lookup, so I would define pow = math.pow

pow = math.pow
while keep_searching:
 a += 1
 a5 = pow(a, 5)
 for b in range(1, a+1):
 b5 = pow(b, 5)
 for c in range(1, b+1):
 sum_begin = a5 + b5 + pow(c, 5)
 for d in range(1, c+1):
 sum = sum_begin + pow(d, 5)
 ...

Also note that python has an official style-guide, PEP8, which recommends putting spaces around operators and after commas in argument lists (I applied those rules in the code above).

Note that str.format does not care what it's parameters are. It will just call str on them and use that. So no need to call int on your parameters (they are already ints anyway).

answered Sep 12, 2016 at 18:55
\$\endgroup\$
2
  • \$\begingroup\$ Python Power lookup stores fifth powers in an array. It Computes n^5 by calling arr[n] and it computes n^(1/5) by a binary search within 'arr. \$\endgroup\$ Commented Sep 12, 2016 at 19:05
  • \$\begingroup\$ @Stepan Not sure I missed some code or your edit added it. The way it is now, yes your array approach is better. However, storing the intermediate results is also a valid (and easy) improvement on your other method. \$\endgroup\$ Commented Sep 12, 2016 at 19:52
1
\$\begingroup\$

C++ bruteforce ~3 s, C++ reference lookup - 0.25 s.

This code has several problems:
(1) math.pow(a,5) is way slower than a**5

(2) It calculates a^5 each time d changes. Rather it should be

for c in range(1,b+1):
 a5b5c5=a5b5+c**5 #c^5 is incremented and a partial sum a^5+b^5+c^5 is calculated

(3) Lists and lookup work blazing fast in C++ (due to the way pointers work), but not in Python. Use set instead.

Adding fifth powers to a set and checking if a^5+b^5+c^5+d^5 is a number in the set is the way to go in Python. With these tweaks code executes in 2 seconds and is faster than the original implementation in C++.

answered Sep 18, 2016 at 15:00
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.