Reputation: 5563
So I was writing a simple script to demonstrate geometric series convergence.
from decimal import *
import math
initial = int(input("a1? "))
r = Decimal(input("r? "))
runtime = int(input("iterations? "))
sum_value=0
for i in range(runtime):
sum_value+=Decimal(initial * math.pow(r,i))
print(sum_value)
When I use values such as:
a1 = 1
r = .2
iterations = 100000
I get the convergence to be 1.250000000000000021179302083
When I replace the line:
sum_value+=Decimal(initial * math.pow(r,i))
With:
sum_value+=Decimal(initial * r ** i)
I get a more precise value, 1.250000000000000000000000002
What exactly is the difference here? From my understanding, it has to do with math.pow
being a floating point operation, but I would just think that **
is syntactic sugar for the math power function. If they are indeed different, then why with a precision value of 200, when inputting the following to IDLE:
>>> Decimal(.8**500)
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
>>> Decimal(math.pow(.8,500))
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
They seem to be exactly the same. What is happening here?
Upvotes: 2
Views: 1035
Reputation: 6891
The difference is, as you imply, that math.pow()
converts the inputs to float
s as stated in the documentation: "Unlike the built-in ** operator, math.pow() converts both its arguments to type float."
Therefore math.pow()
also delivers a float
as answer, independently of whether the input is Decimal
(or int
) or whatever. When using numbers that are not exactly representable as a float
(but is as Decimal
) you are likely to get a more precise answer using the **
operator.
This explains why your loop gives a more exact result in case of using **
since you are working with Decimal
numbers raised to an integer. In the second case, you are inadvertently using float
s for both calculations and then converting the result to Decimal
when the operation is already executed. If you instead work with explicit Decimal
values you will see the difference:
>>> Decimal('.8')**500
Decimal('3.507466211043403874762758796E-49')
>>> Decimal(math.pow(Decimal('.8'), 500))
Decimal('3.50746621104350087215129555150772856244326043764431058846880005304485310211166734705824986213804838358790165633656170035364028902957755917668691836297512054443359375E-49')
Thus, in the second case, the Decimal
value is automatically casted to a float
and the result is the same as for your example above. In the first case, however, the calculation is executed in the Decimal
domain and yields a slightly different result.
Upvotes: 3