Some timings may be of interest.
Note that procedure f below can go awry for obtaining the 1st digit of n=10^N where N is of type nonnegint. That is easily done without Maple, of course, but it's undesirable to have unnecessary corner cases in one's code.
Also, as given procedure nthdigit doesn't allow a float as the first argument. The others do, ignoring the decimal point (but that could be accommodated differently).
None of these check whether n has few than k digits.
The first approach g below computes a float approximation and then picks off the mantissa. The command SFloatMantissa could be used instead of op(1,...), if that make it clearer.
There is some savings to be had by using kernel builtin trunc instead of floor, but even with that g will outpace h below to handle 5^(9^6) in the stated example.
These timings were done in 64bit Maple 17.01 on Windows 7. There may be differences if using 32bit Maple, for some examples, since the cutoff for immediate integers is smaller.
restart:
g:=proc(x, d)
Rounding:=-infinity;
op(1,evalf[d](x)) mod 10;
end proc:
CodeTools:-Usage( g(5^(9^5), 87) );
memory used=217.98KiB, alloc change=0 bytes, cpu time=0ns, real time=2.00ms
8
CodeTools:-Usage( g(5^(9^6), 87) );
memory used=1.97MiB, alloc change=0 bytes, cpu time=16.00ms, real time=19.00ms
6
restart:
h:=proc(x, d)
floor(x/10^((ilog[10](x)+1)-d)) mod 10;
end proc:
CodeTools:-Usage( h(5^(9^5), 87) );
memory used=0.77MiB, alloc change=0 bytes, cpu time=0ns, real time=5.00ms
8
CodeTools:-Usage( h(5^(9^6), 87) );
memory used=6.29MiB, alloc change=0 bytes, cpu time=62.00ms, real time=61.00ms
6
restart:
f:=proc(x, d)
floor(x/10^(ceil(log[10](x))-d)) mod 10;
end proc:
CodeTools:-Usage( f(5^(9^5), 87) );
memory used=18.21MiB, alloc change=24.00MiB, cpu time=109.00ms, real time=113.00ms
8
CodeTools:-Usage( f(5^(9^6), 87) );
memory used=179.28MiB, alloc change=17.53MiB, cpu time=1.62s, real time=1.62s
6
restart:
nthdigit := proc (n, k)
local d, m;
d := convert(n, base, 10);
m := nops(d);
return d[m+1-k];
end proc:
CodeTools:-Usage( nthdigit(5^(9^5), 87) );
memory used=344.99MiB, alloc change=51.50MiB, cpu time=843.00ms, real time=851.00ms
8
CodeTools:-Usage( nthdigit(5^(9^6), 87) );
memory used=26.74GiB, alloc change=26.84MiB, cpu time=55.21s, real time=54.76s
6
Also, somewhat fast (but not faster than g or h above) is,
restart:
s:=proc(x, d)
parse(StringTools:-Substitute(sprintf("%a",x),".","")[d]);
end proc:
CodeTools:-Usage( s(5^(9^5), 87) );
memory used=1.26MiB, alloc change=0 bytes, cpu time=0ns, real time=12.00ms
8
CodeTools:-Usage( s(5^(9^6), 87) );
memory used=16.15MiB, alloc change=0 bytes, cpu time=124.00ms, real time=115.00ms
6
By the way, is there supposed to be some super fast way? Ie, was is a challenge or competition question of some sort?
5^(9^6)it takes a fast Intel i7 over 50 seconds in 64bit Maple 17. The result can be found in a few milliseconds with various other simple approaches using Maple. – acer Sep 17 '13 at 23:57