On Fri, Feb 23, 2018 at 3:00 AM, Steven D'Aprano
<steve+comp.lang.pyt...@pearwood.info> wrote:
> On Thu, 22 Feb 2018 12:03:09 +0000, bartc wrote:
>> Here's another speed-up I found myself, although it was only 50 times
>> faster, not 17,000: just write the code in C, and call it via
>> os.system("fib.exe").
> Did you include the time taken to capture the text output from stdout,
> parse it, and convert to an int?

Relatively trivial compared to the overhead of invoking a subprocess
THROUGH A SHELL. On Windows, that has to invoke cmd.exe; on Unix-like
systems, most likely /bin/sh. And then that has to search the system
path (maybe that doesn't happen on his Windows system, as presumably
it's finding the executable on the cwd check). That's file system
operations, and a lot of them.

> Did your C code support numbers greater than 2**64? My fibonacci function
> can calculate the 10,000th Fibonacci number in a blink of the eye:
> py> fibi(10000)
> 336447648764317832666216120051075...976171121233066073310059947366875
> Output truncated for brevity, it is a 2090-digit number.
> Admittedly it did take about a minute and a half to generate all 208988
> digits of the one millionth Fibonacci number, but the performance is fast
> enough for my needs.

Yeah, but if you stick that into a variable, you can separately time
the calculation from the stringification. Using the exact code from
the page:

def fib_seq(n):
    if n < 2:
        return n
    a,b = 1,0
    for i in range(n-1):
        a,b = a+b,a
    return a

>>> time.time(); x = fib_seq(1000000); time.time()

That's seven seconds to calculate the number. How big a number is it?

>>> x.bit_length()
>>> math.log10(x)

Both take effectively zero time. Dividing that number by 10 that many
times is what takes all the processing. (Stringifying a number
basically consists of div-mod to trim off the last digit, keep going
until you run out of number. Lots of division.)

So actually calculating the millionth Fibonacci number can be done
fairly quickly; figuring out its first digits would be hard, but we
don't actually need that. Though we could probably get a decent

>>> log = math.log10(x)
>>> print(10**(log - int(log)), "e +", int(log))
1.9532821287892859 e + 208987

I wouldn't trust all of those digits, but that's a fast way to get an
idea of the scale of a number. Doing that rather than printing the
whole number means you actually see the performance of *calculation*.


Reply via email to