Reputation: 1187
I am preparing for competitive programming in python. I was guessing if I should use max()
at all with consideration of performance impact. So I quickly tried following:
import time
def compare(i, j, num_iterations):
start = time.process_time_ns()
for i in range(num_iterations):
m = max(i,j)
end = time.process_time_ns()
print('t(max): ' + str(end - start))
start = time.process_time_ns()
for i in range(num_iterations):
if i < j:
m = j
else:
m = i
end = time.process_time_ns()
print('t(if): ' + str(end - start))
start = time.process_time_ns()
for i in range(num_iterations):
m = j if i < j else i
end = time.process_time_ns()
print('t(?:): ' + str(end - start))
compare(0,1,10000)
print()
compare(0,1,100000)
print()
compare(0,1,1000000)
print()
compare(0,1,100000000)
The output was:
t(max): 0
t(if): 0
t(?:): 0
t(max): 0
t(if): 15625000
t(?:): 0
t(max): 109375000
t(if): 31250000
t(?:): 31250000
t(max): 13765625000
t(if): 5265625000
t(?:): 4953125000
Seems that max()
is indeed slower than the simple if-else
. Is it the case?
Upvotes: 1
Views: 893
Reputation: 5944
Yes:
def _if(i, j):
return i if i > j else j
In [328]: %timeit max(1, 0)
200 ns ± 5.73 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%timeit max(0, 1)
195 ns ± 3.07 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%timeit _if(0, 1)
136 ns ± 1.39 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
In [367]: %timeit _if(1, 0)
127 ns ± 0.47 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Why?
Obviously enough because of _if(0,1,2)
(which is illegal). The _if
function here isn't a replacement for max
at all, and in this special case (picking the biggest of two operands) a simple comparison is (currently) cheaper (although nothing prevents an implementation optimising max
for this case).
That said a few ns is unlikely to dominate. When you get to that kind of worry you start avoiding functions at all, and you're arguably better off with a compiled language where you can let the compiler worry about things like inlining.
I highly doubt any programming competition focused on 'performance' will be decided on things like this (more likely on getting your higher-level algorithms right for the problem at hand). But what do I know: there's always a counter-example.
Upvotes: 1
Reputation: 106
This if/else statement is only comparing 1 and 0. Yes you are doing many iterations, but this wouldnt be a practical case for using max.
your if/else would be much slower when getting the max value from a list of 100000 random numbers between 0-100000. The alternative to using max is to sort and get the last element.
import random
@profile
def main():
rand_list = random.sample(range(0,100000), 100000)
print(max(rand_list))
@profile
def main2():
rand_list = random.sample(range(0,100000), 100000)
print(sorted(rand_list)[-1])
@profile
def main3():
rand_list = random.sample(range(0,100000), 100000)
count = 0
for i in rand_list:
if count < i:
count = i
print(count)
main()
main2()
main3()
Running
python3 -m kernprof -l -v testing.py
99999
99999
99999
Wrote profile results to testing.py.lprof
Timer unit: 1e-06 s
Total time: 0.149179 s
File: testing.py
Function: main at line 3
Line # Hits Time Per Hit % Time Line Contents
==============================================================
3 @profile
4 def main():
5 1 147971.0 147971.0 99.2 rand_list = random.sample(range(0,100000), 100000)
6 1 1208.0 1208.0 0.8 print(max(rand_list))
Total time: 0.164449 s
File: testing.py
Function: main2 at line 8
Line # Hits Time Per Hit % Time Line Contents
==============================================================
8 @profile
9 def main2():
10 1 150492.0 150492.0 91.5 rand_list = random.sample(range(0,100000), 100000)
11 1 13957.0 13957.0 8.5 print(sorted(rand_list)[-1])
Total time: 0.193634 s
File: testing.py
Function: main3 at line 13
Line # Hits Time Per Hit % Time Line Contents
==============================================================
13 @profile
14 def main3():
15 1 150456.0 150456.0 77.7 rand_list = random.sample(range(0,100000), 100000)
16 1 1.0 1.0 0.0 count = 0
17 100001 20864.0 0.2 10.8 for i in rand_list:
18 100000 22296.0 0.2 11.5 if count < i:
19 13 2.0 0.2 0.0 count = i
20 1 15.0 15.0 0.0 print(count)
In a practical use case for max it will be faster.
Upvotes: 1