# Why is computing $e^x$ faster than computing $2^x$?

One time, I decided to test how long it takes to compute $$2^x$$ compared to $$e^x$$ in Python. I expected $$2^x$$ to be faster as in binary, the base computers use, you can just append 0 to the number 1 $$x$$ times. I entered into Python IDLE (Python's Integrated Development and Learning Environment):

>>> import timeit
>>> timeit.timeit('2**100')
>>> 0.24405850004404783
>>> timeit.timeit('e**100','e=2.718281828459045')
>>> 0.10122330003650859


and found that $$e^x$$ was about twice as fast to compute, despite not being an integer. Why does this happen? (Note that this only happens for large numbers.) The only reason I can think of is that $$e^x$$ can be easily calculated using a MacLaurin series as $$\frac d{dx} e^x$$ is equal to $$e^x$$.

• Using 3.5.2 on an ancient clunker, I get the reverse relation even using timeit.timeit('total += e**100', "e, total =2.718281828459045, 0"): What is your platform? Commented May 14, 2023 at 8:51
• @greybeard I am using IDLE (meaning python 3.10.11) and running it on a Windows 11 laptop. Model name for laptop is ideapad Flex 5. Commented May 14, 2023 at 9:00
• >>> timeit.timeit('2.0**100') >>> 0.0073371000000008735 Commented May 14, 2023 at 10:04
• Compare the outputs of both calculations. You get one exact result an one approximation. The "just append 0 bits" fails because the number gets bigger than 64 bit (common register size for integers) can handle. Commented May 14, 2023 at 10:47
• I do not believe it's actually using taylor series for computing large exponential anyway. Commented May 14, 2023 at 13:27

You are not comparing the same operations. You are comparing two operations that look very similar in source code, but they are very much different.

2**100 takes an integer 2, and calculates that integer raised to the 100th power using unlimited precision integer arithmetic. If you tried 2*1000000 you would get a number with about 300,000 digits containing the exact value of 2**100.

e**100 with e = 2.718281828459045 takes a floating-point number and raises it to the 100th power using limited floating-point precision. This will not give you more than about 15 digits precision and will fail with overflow when the exponent is about 800 or so. It is a total different operation. So obviously takes a very different amount of time.

The reason is simple: 2**100 returns a bignum, with full accuracy. There is more work to handle the bignum representation than mere binary shifts. On the opposite, e**100 returns a float and uses the built-in power function of the processor.

>>> from timeit import timeit
>>> timeit('2**100')
0.20831729998462833
>>> timeit('2.0**100')
0.008533199987141415
>>> timeit('2.718281828459045**100')
0.008684300002641976
>>> timeit('e**100', 'e=2.718281828459045')
0.10991410000133328
>>> timeit('e**100', 'from math import e')
0.10929809999652207

• Can you explain how the built-in function is faster? Commented May 14, 2023 at 9:45
• @PlaceReporter99: bignums are not built-in, they are emulated in software.
– user16034
Commented May 14, 2023 at 9:58
• If that's the explanation it's a minor miracle that the difference is only a factor of 2. Mind, I'm not doubting you. e**100 is still well within floating point range. In fact now I'm wondering if the time for that is not overly long. Commented May 14, 2023 at 15:31
• @VictorEijkhout: why ? $200$ or $100$ nanoseconds seem reasonable.
– user16034
Commented May 14, 2023 at 15:36
• I always thought that timeit gave values in seconds. Commented May 14, 2023 at 16:06