When using integers with ** operand, the speed is considerably slower than if using at least one float argument.
After a few runs, I get consistenly these results:
% time {expr {5.0**2}} 10000
3.6763 microseconds per iteration
% time {expr {5**2.0}} 10000
3.6791 microseconds per iteration
% time {expr {double(5)**2}} 10000
5.4605 microseconds per iteration
% time {expr {5**double(2)}} 10000
5.693 microseconds per iteration
% time {expr {5**2}} 10000
38.9746 microseconds per iteration
just to compare with the other "traditional" ways to obtain 5**2
% time {expr {5*5}} 10000
2.7841 microseconds per iteration
% time {expr {pow(5,2)}} 10000
7.7954 microseconds per iteration
% info patchlevel
8.5a6
Don Porter
2007-08-04
Don Porter
2007-08-06
Don Porter
2007-08-06
Logged In: YES
user_id=80530
Originator: NO
When at least one of the arguments is double,
the operation turns into a pow() call at the
C level, so it's comparable performance to
[expr {pow(...)}] minus Tcl function call overhead.
When both are integer, the current implementation
is an iterative one. It's worth looking for improvements,
but only to the extent that the current performance
isn't "fast enough". Patches welcome; otherwise I'll
get to this when I get to it.
Don Porter
2007-08-06
Logged In: YES
user_id=80530
Originator: NO
Aha! Spoke too soon.
Root cause of this one is found at
line 5240 of Revision 1.309 of
tclExecute.c:
/* TODO: Perform those computations that fit in native types */
Since code to detect and perform those
computations that fit in native types isn't
done yet, all non-trivial integer ** operations
get done as bignums.
Patch still welcome. Normal priority restored.
Don Porter
2007-08-06
Kevin B KENNY
2007-08-06
Logged In: YES
user_id=99768
Originator: NO
The attached patch is working toward a solution.
Observation #1: Powers of 2 are the same as shifts of 1, and are handled thus.
Observation #2: For 32-bit integers, a very efficient exponent can be computed by doing special-case straight-line code for raising to powers 3-8, and then using table lookups for higher powers (up to 3**19 and up to 10**10).
Observation #3: For 64-bit integers, a similar computation can be done with straight-line code for raising to powers 3-16, and then table lookup for higher powers (up to 3**39
and up to 14**17).
I haven't tried to implement #3, because I'm none too certain how to initialize
Tcl_WideInts at compile time with values that don't fit in an int.
The patch should be commitable as it stands (resulting in performance gains only on 32-bit machines), but obviously #3 is important, too.
File Added: power.patch
Kevin B KENNY
2007-08-06
Logged In: YES
user_id=99768
Originator: NO
On Win32 (mingw), the patch is observed to fix the performance anomaly:
% time {expr {5*5}} 100000
0.63991 microseconds per iteration
% time {expr {5**2}} 100000
0.62671 microseconds per iteration
% time {expr {pow(5,2)}} 100000
1.68862 microseconds per iteration
% time {expr {5*5*5*5*5}} 100000
0.91689 microseconds per iteration
% time {expr {5**5}} 100000
0.72139 microseconds per iteration
% time {expr {pow(5,5)}} 100000
1.65471 microseconds per iteration
The performance penalty is still there when quantities overflow from a 32-bit integer; we're still working on that one:
% time {expr {3**19}} 100000; # this fits in a 32-bit word
0.61131 microseconds per iteration
% time {expr {3**20}} 100000; # this doesn't
5.84269 microseconds per iteration
Kevin B KENNY
2007-08-07
Logged In: YES
user_id=99768
Originator: NO
Updated patch:
- handles negative exponents correctly (first one had a bug)
- handles powers up to and including x**16 with 'wide' results
- does not handle higher powers with 'wide' results.
File Added: power.patch
Kevin B KENNY
2007-08-07
Logged In: YES
user_id=99768
Originator: NO
One more try - powers of -2 were still not right.
File Added: power.patch
Don Porter
2007-08-07
Logged In: YES
user_id=80530
Originator: NO
failing tests mathop-(20.3,25.6,25.13)