Python for philosophers
88888 Dihedral
dihedral88888 at googlemail.com
Sat May 18 19:56:41 EDT 2013
Chris Angelico於 2013年5月14日星期二UTC+8上午12時24分44秒寫道:
> On Tue, May 14, 2013 at 12:53 AM, rusi <rustompmody at gmail.com> wrote:
>
> > int fact(int n, int acc)
>
> > {
>
> > return !n? acc : fact(n-1,acc*n);
>
> > }
>
> > ---------------------------------
>
> > When I run these, the C happily keeps giving answers until a million
>
> >
>
> > However examined closely we find that though the C is giving answers
>
> > its giving junk after around 12
>
> > fact 17 is -288522240
>
> > And 35 onwards its 0 (!!)
>
>
>
> That'll depend on your integer size. If it's a 32-bit integer, you
>
> can't store numbers greater than 2**31-1 (if you declared it as
>
> 'unsigned int', you could go all the way to 2**32-1). I'm sure you
>
> could write this to use the GNU Multi-Precision library, but it'd be a
>
> lot more complicated. However, as far as I know, the Turing machine
>
> never promises that; its cells aren't meant to be infinite integers.
>
>
>
> The Python script is, of course, governed by sys.setrecursionlimit().
>
> But by adding a simple driver, we can test the real limit:
>
>
>
> import sys
>
>
>
> def fact(n,acc=1):
>
> return acc if not n else fact(n-1,n*acc)
>
>
>
> n=2
>
> while True:
>
> sys.setrecursionlimit(n+2)
>
> print("fact",n,"has",len(str(fact(n))),"digits")
>
> n*=2
>
>
>
> On my 64-bit system, running a recent trunk build of CPython 3.4, it
>
> can calculate 8192! but not 16384! (segfault). The limit seems to be
>
> 12772; after that, boom. Your crash-point will quite probably vary,
>
> and I'd say there'll be compile-time options that would change that.
>
>
>
> Of course, after playing with this in Python, I had to try out Pike.
>
> Using the exact same code you proposed for C, but with a different
>
> main() to save me the hassle of keying in numbers manually, I get
>
> this:
>
>
>
> fact 8192 has 28504 digits - 0.026 secs
>
> fact 16384 has 61937 digits - 0.097 secs
>
> fact 32768 has 133734 digits - 0.389 secs
>
> fact 65536 has 287194 digits - 1.628 secs
>
> fact 131072 has 613842 digits - 7.114 secs
>
> fact 262144 has 1306594 digits - 31.291 secs
>
> fact 524288 has 2771010 digits - 133.146 secs
>
>
>
> It's still going. One core consumed, happily working on 1048576!, and
>
> not actually using all that much memory. Hmm.... looks like the Pike
>
> optimizer has turned this non-recursive. Okay, let's tweak it so it's
>
> not tail-recursion-optimizable:
>
>
>
> return n?n*fact(n-1,1):1;
>
>
>
> Now it bombs at 65536, saying:
>
>
>
> Svalue stack overflow. (99624 of 100000 entries on stack, needed 256
>
> more entries)
>
>
>
> Hey, it's better than a segfault, which is what C would have done :)
>
> And it's a tweakable value, though I don't know what the consequences
>
> are of increasing it (presumably increased RAM usage for all Pike
>
> programs).
>
>
>
> Your final conclusion is of course correct; nothing we build can be
>
> truly infinite. But we can certainly give some very good
>
> approximations, if we're prepared to pay for them. The reality is,
>
> though, that we usually do not want to pay for approximations to
>
> infinity; why is IEEE 754 floating point so much more used than, say,
>
> arbitrary-precision rational? Most of the time, we'd rather have good
>
> performance and adequate accuracy than abysmal performance and perfect
>
> accuracy. But hey, if you want to render a Mandelbrot set and zoom in
>
> to infinity, the option IS there.
>
>
>
> ChrisA
Hey, ChisA, are you delibrately to write a recursive version
to demonstrate the stack depth problem in Python?
def fact(n):
ret=1
if n>1: # integer checking is not used but can be added
for x in xrange(n): ret*=x
#print ret # debugging only for long integers
return ret
In a 32 or 64 bit system, this non-recursive verssion
will be limited by the heap space not by the stack limit.
More information about the Python-list
mailing list