I've had the benefit of reading the other answers. For starters people like me should know the reason why we're dealing with such a huge integer here is that both Python
and bc
do right-associative exponentiation expansion, which means that this is not 6^36
we're evaluating but rather 6^46656
which is considerably larger.1
Using variations on the following commands, we can extract an average for a specific element of the output of both the time
reserved word and command:
for i in {1..1000}; do (time echo 6^6^6 | bc > /dev/null) 2>&1; done | grep 'rea' | sed -e s/.*m// | awk '{sum += $1} END {print sum / NR}'
for i in {1..1000}; do (/usr/bin/time -v sh -c 'echo 6^6^6 | bc > /dev/null') 2>&1; done | grep 'Use' | sed -e s/.*:// | awk '{sum += $1} END {print sum / NR}'
It is possible to go another route and remove the file entirely from the comparison. Also, we can compare bc's timing with something like the dc
command, as historically the former is a "front end processor" to the latter. The following commands were timed:
echo 6^6^6 | bc
echo 6 6 6 ^ ^ p | dc
echo print 6**6**6 | python2.7
Note the dc
command is left-associative for exponentiation.2
We have some results with time
(bash) for 1000 iterations (in seconds):
0.229678 real bc
0.228348 user bc
0.000569 sys bc
0.23306 real dc
0.231786 user dc
0.000395 sys dc
0.07 real python
0.065907 user python
0.003141 sys python
bc
and dc
offer comparable performance in this context.
Less accurate3 results from /usr/bin/time
i.e. GNU time
command (scale precision is not valid here but the results are similar):
0.2224 user bc
0 sys bc
0.23 Elapsed bc
0.22998 user dc
0 sys dc
0.23 Elapsed dc
0.06008 user python
0 sys python
0.07 Elapsed python
An advantage of /usr/bin/time
is that it offers the -v
option which yields much more information which could be useful eventually.
It is also possible to evaluate this internally so to speak with the timeit
Python module:
python2.7 -m timeit -n 1000 -r 1 'print 6**6**6' | grep 'loops'
1000 loops, best of 1: 55.4 msec per loop
That's a bit faster than what we saw before. Let's try the interpreter itself:
>>> import timeit
>>> import sys
>>> import os
>>> T = timeit.Timer("print 6**6**6")
>>> n = int(1000)
>>> f = open(os.devnull, 'w')
>>> sys.stdout = f
>>> t = t.timeit(n)
>>> sys.stdout = sys.__stdout__
>>> print t/n
0.0553743481636
That's the quickest I've seen.
If we evaluate a lesser exponentiation like 6^6
, then the time command yields surprising results - using the same for
loop commands we used we now have:
0.001001 bc real
0.000304 user
0.000554 sys
0.014 python real i.e. 10x more than bc??
0.010432 user
0.002606 sys
So with a smaller integer bc
is all of a sudden much faster?? From system reboot to second run makes no difference. Yet at the same time, if we use timeit
for Python, we get:
python2.7 -m timeit -n 100000 -r 1 'print 6**6' | grep loops
100000 loops, best of 1: 0.468 usec per loop
This is microseconds, not milliseconds, so this doesn't match with the much slower results using the for
loop. Maybe other tools are required to test this further and as others have explained there's more than meets the eye here. It seems Python was faster in the question's scenario but it's not clear if conclusions can be drawn beyond that...
1. Needless to say it's beyond the scope of something like echo's
arithmetic expansion i.e. echo $((6**6**6))
- bash
also happens
to be right-associative for that i.e. 6^6^6 = 6^(6^6)
.
2. Compare with this: 6 6 ^ 6 ^ p
.
3. It's possible the GNU time command provides more info when run on BSD UNIX (GNU time info document):
Most information shown by 'time' is derived from the 'wait3' system call. The numbers are only as good as those returned by 'wait3'. Many systems do not measure all of the resources that 'time' can report on; those resources are reported as zero. The systems that measure most or all of the resources are based on 4.2 or 4.3BSD. Later BSD releases use different memory management code that measures fewer resources. -- On systems that do not have a 'wait3' call that returns status information, the 'times' system call is used instead. It provides much less information than 'wait3', so on those systems 'time' reports most of the resources as zero.
echo | bc
involves launching a subshell because of the pipe -- that's where some of your extra user time probably came from. To make this an equitable test, the python script should read from stdin so you cantime echo 6**6**6 | whatever.py
. – goldilocks Feb 21 '14 at 17:55echo 6^6^6 | time bc
. – daniel kullmann Feb 21 '14 at 18:226**6**6
expression is actually computed at compile time. However since you are launching the file directly instead of importing it from a module, this shouldn't matter. To see the difference put10**12345678
into ana.py
file and try to import it from the interactive interpreter. Then close the interpreter, restart it and importa
again. The first time it should take an noticeable amount of time (because python is compiling the module), while the second time it loads the.pyc
, which should be instantaneous, – Bakuriu Feb 21 '14 at 19:07