Why Does Python "Preemptively" Hang When Trying to Calculate a Very Large Number

Why does time incorrectly report such a fast time?

python.exe and pythonw.exe are optimizing the code before running. It seems that the 2**100000000 is being pre-computed. This small edit to the code:

import time

print("program entered")

def ispow2(n):
return not n & n - 1

start = time.perf_counter()
ispow2(2**100000000)
end = time.perf_counter()

print(end - start)

Produces the following output completely after the wait:

program entered
0.01701506924359556

So the program doesn't even run until after the majority of the wait.

Data that suggests that this is with the 2**... part (running from command line):

power of two|approximate wait time|reported time
1000000000 | 6 seconds |0.1637752267742188
10000000000 | 62 seconds |1.6400543291627092

On that last run, there was a clear ~1.5 second wait between the output of program entered and 1.6400543291627092.

Why does IDLE 3.4 take so long on this program?

I would look at that line and pick it apart. You have:

9 << (1 << 26)

(1 << 26) is the first expression evaluated, and it produces a really large number. What this line is saying, is that you are going to multiply the number 1 by 2 to the power of 26, effectively producing the number 2 ** 26 in memory. This is not the problem however. You then shift 9 left by the count of 2 ** 26. This produces a number that is around 50 million digits long in memory (I cant even calculate it exactly!), because the shift left is just too big. Be careful in the future, as shifts by what seems to be small amounts do in fact grow very fast. If it was any larger, your program may have not run at all. Your expression mathematically evaluates to 9 * 2 ** (2 ** 26), if you were curious.

The ambiguity in the comment section is probably actually dealing with how this huge portion of memory is handled by python under the hood, and not IDLE.

EDIT 1:

I thing that what is happening, is that a mathematical expression evaluates to its answer, even when placed inside of a function that isn't called yet, only if the expression is self sufficient. This means that if a variable is used in the equation, the equation will be untouched in the byte code, and not evaluated until hard execution. The function has to be interpreted, and in that process, I think that your value is actually computed, resulting in the slower times. I am not sure about this, but I strongly suspect this behavior to be the root cause. Even if it is not so, you got to admit that 9<<(1<<26) kicks the computer in the behind, there's not much optimization that can be done there.

In[73]: def create_number():
return 9<<(1<<26)
In[74]: #Note that this seems instantaneous, but try calling the function!
In[75]: %timeit create_number()
#Python environment crashes because task is too hard

There is a slight deception in this kind of testing however. When trying this with the regular timeit, I got:

In[3]: from timeit import timeit
In[4]: timeit(setup = 'from __main__ import create_number', stmt = 'create_number()', number = 1)
Out[4]: .004942887388800443

Also keep in mind that printing the value is not do-able, so something like:

In[102]: 9<<(1<<26)

should not even be attempted.

For even more added support:

I felt like a rebel, so I decided to see what would happen if I timeit the raw execution of the equation:

In[107]: %timeit 9<<(1<<26)
10000000 loops, best of 3: 22.8 ns per loop

In[108]: def empty(): pass
In[109]: %timeit empty()
10000000 loops, best of 3: 96.3 ns per loop

This is really fishy, because apparently this calculation happens faster than the time it takes Python to call an empty function, which is obviously not the case. I repeat, this is not instantaneous, but probably has something to do with retrieving an already calculated object somewhere in memory, and reusing that value to calculate the expression. Anyways, nice question.

Error when trying to print a number of messages spread across one second

I think it should be time.time() - start.

import time
import sys
duration = 1.0
target = 40

start = time.time()
count = 0
while True:
print("Hello")
count = count + 1
target -= 1
if count == 40:
sys.exit(0)
if target:
time.sleep((duration + time.time() - start) / target)
else:
start = time.time()
target = 40

How to avoid math.sin(math.pi*2*VERY LARGE NUMBER) having a much larger error margin than math.sin(math.pi*2)?

This simply isn't going to work with double-precision variables.

The value of math.pi is correct only to about 16 places of decimals (53 bits in binary), so when you multiply it by a number like 415926535897932384626433832795028841971693993751 (159 bits), it would be impossible to get meaningful results.

You need to use an arbitrary precision math library instead. Try using mpmath for example. Tell it you want 1000 bits of precision, and then try your sums again:

>>> import mpmath
>>> mpmath.mp.prec=1000
>>> print(mpmath.sin((mpmath.pi*2*(415926535897932384626433832795028841971693993751))+(mpmath.pi/2)))
1.0

Cost of using 10**9 over 1000000000?

It's more about readability and coding style. By writing something like 10**9 instead of 1000000000 or etc., you'll make your code shorter and more readable, thus its maintenance and improvement would be easier. If you want to use 10**9 multiple times in your code, as a more elegant way you'd better use it as a global variable at the top level of your module which is more elegant. Like:

MY_VARIABLE = 10**9

Note that even if you don't use a global variable name and use its numerical value through your code python will assume it's a constant value and won't recalculate it every time.

For example, as you can see in the following bytecode, python will load the constant value (which you defined in first part for a) for c and doesn't create a new object 1 for that:

>>> def test():
... a = 10**9
... b = 1000000000
... c = 10**9
...
>>> dis.dis(test)
2 0 LOAD_CONST 4 (1000000000)
3 STORE_FAST 0 (a)

3 6 LOAD_CONST 3 (1000000000)
9 STORE_FAST 1 (b)

4 12 LOAD_CONST 5 (1000000000)
15 STORE_FAST 2 (c)
18 LOAD_CONST 0 (None)
21 RETURN_VALUE


Note that python small integers are singletons and python will create only one copy of them (-5 to 256).

Python/Mpmath: Why don't I get any decimal points for large number division, but do for smaller numbers

Try using mpf(x)/6 or mpf(x)/6.0. The reason your code didn't work is that it did the division using Python's normal rules, then converted it to a arbitrary-precision number, whereas this converts it first so the division is done using arbitrary-precision math.



Related Topics



Leave a reply



Submit