This code is used to estimate pi, with the highest objective being time efficiency. With this in mind, I need to increase the amount of decimal places, as currently it is bottlenecked down to 2.
import numpy as np
def main(max_iterations=200):
a, b= np.random.random(max_iterations), np.random.random(max_iterations)
return 4 * (a ** 2 + b ** 2 < 1).sum() / max_iterations
main()
Example of current output:
3.13
One thing I noticed was that upon adding 0s to the max_iterations parameter, the number of decimal places increased along with it. Though, I need a solution within the function, where it wouldn't matter what the value of the parameter was.
Example of what I want as an output:
3.127722772277228
Don't divide an integer by a number with trailing zeros if you want more significance.
With max_iterations=200:
%Run pi_test.py
3.08
With max_iterations=201:
%Run pi_test.py
3.084577114427861
Related
I've read in other questions that that for example sin(2π) is not zero due to floating point representation, but is very close. This very small error is no issue in my code as I can just round up 5 decimals for example.
However when multiplying 2π with a very large number, the error is magnified a lot. The answer should be zero (or close), but is far from it.
Am I doing something fundamentally wrong in my thinking? If not, how can I avoid the error margin of floating numbers for π to get "magnified" as the number of periods (2*PI*X) → ∞ ?
Notice that all the 3 last results are the same. Can anyone explain why this is even though 5) is exactly PI/2 larger than 4)? Even with a huge offset in the sinus curve, an increase in PI/2 should still produce a different number right?
Checking small number SIN(2*PI)
print math.sin(math.pi*2)
RESULT = -2.44929359829e-16 AS EXPECTED → This error margin is OK for my purpose
Adding PI/2 to code above: SIN(2*PI + PI/2)
print math.sin((math.pi*2)+(math.pi/2))
RESULT: 1.0 AS EXPECTED
Checking very large number SIN(2*PI*VERY LARGE NUMBER) (still expecting close to zero)
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
RESULT:-0.759488037749 NOT AS EXPECTED --> This error margin is NOT OK for my purpose
Adding PI/2 to code above: SIN(2*PI*VERY LARGE NUMBER + PI/2) (expecting close to one)
print math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
As above but I added PI/2 - expecting to get 1.0 as result
RESULT:-0.759488037749 NOT AS EXPECTED - why the same result as above when I added PI/2 (should go a quarter period on the sinus curve)
Adding random number (8) to the very large number, expecting neither 1 nor 0
print math.sin(math.pi*2*(415926535897932384626433832795028841971693993759))
as above but I added 8 - expecting to get neither 0 nor 1
RESULT:-0.759488037749 NOT AS EXPECTED - why the same result as above when I added 8
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
How to avoid math.sin(math.pi*2*VERY LARGE NUMBER) having a much larger error margin than math.sin(math.pi*2)?
You could % 1 that very large number:
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751))
-0.8975818793257183
>>> math.sin(math.pi*2*(415926535897932384626433832795028841971693993751 % 1))
0.0
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751))+(math.pi/2))
-0.8975818793257183
>>> math.sin((math.pi*2*(415926535897932384626433832795028841971693993751 % 1))+(math.pi/2))
1.0
The algorithms used are approximate, and the values (e.g. pi) are approximate. So $\pi \cdot {SomeLargeNumber}$ will have a largeish error (as $\pi$'s value is approximate). The function used (by hardware?) will reduce the argument, perhaps using a slightly different value of $\pi$.
Note that floating point arithmetic does not satisfy the axioms for real arithmetic.
Hey i'm a little noob still but i'm playing around with python and i want to round D to it's nearest decimal, C and H are fixed and D is the rawinput, the whole answer should be rounded but i keep getting decimals,i want this formula :
Q = Square root of [(2 * C * D)/H]
her's my code:*
import math
C=50
H=30
D=int(raw_input())
a=int(round(D))
Q= math.sqrt(2*C*a/H)
print Q
if i enter 100 i get 18.24
i just want it to be 18
i would really appreciate your help, thanks
import math
C = 50
H = 30
a = int(raw_input())
# prints as a float
# Q = round(math.sqrt(2 * C * a / H), 0)
# prints as an int
Q = int(round(math.sqrt(2 * C * a / H), 0))
print Q
Your code appears to be rounding in the wrong place. You're rounding the input a, which was already the integer D. You're not rounding the result of the square root Q, which is a float.
Note that you're code actually has an extra rounding step you may not intend in it. When you divide two integers in Python 2, you'll get another integer, even if the computation should have had a remainder. You get floor division, always rounding towards negative infinity, not to the nearest integer (so e.g. 9/10 is 0). In your code, 2*C*a is an integer, since all values you're multiplying are, and so when you divide by h (another integer), it's going to round the division off. In the case you gave where you entered 100 as the user input, you'll get 333 as the result of the division instead of the more precise 333.3333333333333. This in turn makes your square root calculation give a different value (18.24828759089466 instead of 18.257418583505537).
Anyway, you probably want to use floating point values everywhere except maybe at the end when you round off the value before printing it. You almost certainly don't want to be using integer math by accident as your current code does. One way to do that is to turn one of your constant values into a float, and move the rounding to the end:
C=50.0 # make the calculations use floats, rather than ints
H=30
D=int(raw_input()) # no need for `a` anymore, we're rounding later instead
Q= int(round(math.sqrt(2*C*D/H))) # round after taking the square root, not before
An alternative to using C=50.0 is to put from __future__ import division at the top of your file, which tells Python that you want division between integers to return a float. That's the default behavior in Python 3, and it's much nicer most of the time. If you specifically want "floor" division, you can explicitly ask for it with the // operator. You might also consider actually using Python 3, rather than making do with Python 2's forwards compatibility features.
I'm taking few courses about machine learning and I trying to understand this computational issue:
variable = 1000000000 #1 billion
for i in xrange(1000000):
variable = variable+ 1e-6 #0.000001
variable = variable -1000000000 #1 subtracts with 1 billion again
variable
#>> 0.95367431640625
should be 1 but turns out to 0.95367431640625
Can some one tell me why this happens ?
You are losing precision. This is because float in Python implementing double floating point precision which only guarantee precision up to the 15/16-th digit.
When you do:
1,000,000,000 + 0.000001
1,000,000,000.000001 + 0.000001
# and so on, note that you are adding the 16-th digit
# but 1,000,000,000.000001 is not actually exactly 1,000,000,000.000001
# behind is something like 1,000,000,000.000001014819 or 1,000,000,000.000000999819
Continuously, you are breaking the precision limit, there are some other values after the last 1 in the 0.000001 which is represented only as 0.000001. Thus you got accumulative error.
Things would have been different if, say, you initialize your variable as 0. This is because in the computation:
0.000000 + 0.000001
0.000001 + 0.000001
0.000002 + 0.000001
#and so on
Although the actual value of 0.000001 isn't exactly 0.000001, but the 16-th digit imprecision is far from the significant numbers:
0.000000 + 0.00000100000000000000011111
0.000001 + 0.00000100000000000000011111 #insignificant error
You could also avoid the error by using decimal value instead of double:
from decimal import *
variable = Decimal(1000000000)
addition = Decimal(1e-6)
for i in xrange(1000000):
variable = variable+ addition #0.000001
variable = variable-Decimal(1000000000) #1 subtracts with 1 billion again
variable
Python math can't natively handle arbitrary precision. If you want more precise results, it looks like you need to work with decimal module, and even then, be careful:
from decimal import *
x = Decimal(1000000000)
y = Decimal(1e-6)
z = x+y
z
##>> Decimal(1000000000.00000100000000000)
w = z-x
w
##>> Decimal(0.000001000000000000)
## however, when I tried:
bad_x = Decimal(1000000000 + 1e-6)
bad_x
##>> Decimal(1000000000.0000009992934598234592348593458)
The reason bad_x becomes the "wrong" value is because it first did regular ython addition on 1000000000 and 1e-6, which ran into the floating point issue, and then took that (wrong) value and passed it to Decimal - the damage has already been done.
For your use case, it looks like you can make the values into Decimals before adding/subtracting, so you should get the desired results without a problem.
I have some problems due to really low numbers used with numpy. It took me several weeks to trace back my constant problems with numerical integration to the fact, that when I add up floats in a function the float64 precision gets lost. Performing the mathematically identic calculation with a product instead of a sum leads to values that are alright.
Here is a code sample and a plot of the results:
from matplotlib.pyplot import *
from numpy import vectorize, arange
import math
def func_product(x):
return math.exp(-x)/(1+math.exp(x))
def func_sum(x):
return math.exp(-x)-1/(1+math.exp(x))
#mathematically, both functions are the same
vecfunc_sum = vectorize(func_sum)
vecfunc_product = vectorize(func_product)
x = arange(0.,300.,1.)
y_sum = vecfunc_sum(x)
y_product = vecfunc_product(x)
plot(x,y_sum, 'k.-', label='sum')
plot(x,y_product,'r--',label='product')
yscale('symlog', linthreshy=1E-256)
legend(loc='lower right')
show()
As you can see, the summed values that are quite low are scattered around zero or are exactly zero while the multiplicated values are fine...
Please, could someone help/explain? Thanks a lot!
Floating point precision is pretty sensitive to addition/subtraction due to roundoff error. Eventually, 1+exp(x) gets so big that adding 1 to exp(x) gives the same thing as exp(x). In double precision that's somewhere around exp(x) == 1e16:
>>> (1e16 + 1) == (1e16)
True
>>> (1e15 + 1) == (1e15)
False
Note that math.log(1e16) is approximately 37 -- Which is roughly where things go crazy on your plot.
You can have the same problem, but on different scales:
>>> (1e-16 + 1.) == (1.)
True
>>> (1e-15 + 1.) == (1.)
False
For a vast majority of the points in your regime, your func_product is actually calculating:
exp(-x)/exp(x) == exp(-2*x)
Which is why your graph has a nice slope of -2.
Taking it to the other extreme, you're other version is calculating (at least approximately):
exp(-x) - 1./exp(x)
which is approximately
exp(-x) - exp(-x)
This is an example of catastrophic cancellation.
Let's look at the first point where the calculation goes awry, when x = 36.0
In [42]: np.exp(-x)
Out[42]: 2.3195228302435691e-16
In [43]: - 1/(1+np.exp(x))
Out[43]: -2.3195228302435691e-16
In [44]: np.exp(-x) - 1/(1+np.exp(x))
Out[44]: 0.0
The calculation using func_product does not subtract nearly equal numbers, so it avoids the catastrophic cancellation.
By the way, if you change math.exp to np.exp, you can get rid of np.vectorize (which is slow):
def func_product(x):
return np.exp(-x)/(1+np.exp(x))
def func_sum(x):
return np.exp(-x)-1/(1+np.exp(x))
y_sum = func_sum_sum(x)
y_product = func_product_product(x)
The problem is that your func_sum is numerically unstable because it involves a subtraction between two very close values.
In the calculation of func_sum(200), for example, math.exp(-200) and 1/(1+math.exp(200)) have the same value, because adding 1 to math.exp(200) has no effect, since it is outside the precision of 64-bit floating point:
math.exp(200).hex()
0x1.73f60ea79f5b9p+288
(math.exp(200) + 1).hex()
0x1.73f60ea79f5b9p+288
(1/(math.exp(200) + 1)).hex()
0x1.6061812054cfap-289
math.exp(-200).hex()
0x1.6061812054cfap-289
This explains why func_sum(200) gives zero, but what about the points that lie off the x axis? These are also caused by floating point imprecision; it occasionally happens that math.exp(-x) is not equal to 1/math.exp(x); ideally, math.exp(x) is the closest floating-point value to e^x, and 1/math.exp(x) is the closest floating-point value to the reciprocal of the floating-point number calculated by math.exp(x), not necessarily to e^-x. Indeed, math.exp(-100) and 1/(1+math.exp(100)) are very close and in fact only differ in the last unit:
math.exp(-100).hex()
0x1.a8c1f14e2af5dp-145
(1/math.exp(100)).hex()
0x1.a8c1f14e2af5cp-145
(1/(1+math.exp(100))).hex()
0x1.a8c1f14e2af5cp-145
func_sum(100).hex()
0x1.0000000000000p-197
So what you have actually calculated is the difference, if any, between math.exp(-x) and 1/math.exp(x). You can trace the line of the function math.pow(2, -52) * math.exp(-x) to see that it passes through the positive values of func_sum (recall that 52 is the size of the significand in 64-bit floating point).
I have a problem with this question from my professor. Here is the question:
Write the definition of a function typing_speed , that receives two parameters. The first is the number of words that a person has typed (an int greater than or equal to zero) in a particular time interval. The second is the length of the time interval in seconds (an int greater than zero). The function returns the typing speed of that person in words per minute (a float ).
Here is my code:
def typing_speed(num_words,time_interval):
if(num_words >= 0 and time_interval > 0):
factor = float(60 / time_interval)
print factor
return float(num_words/(factor))
I know that the "factor" is getting assigned 0 because its not being rounded properly or something. I dont know how to handle these decimals properly. Float isnt doing anything apparently.
Any help is appreciated, thankyou.
When you call float on the division result, it's after the fact the division was treated as an integer division (note: this is Python 2, I assume). It doesn't help, what does help is initially specify the division as a floating-point division, for example by saying 60.0 (the float version of 60):
factor = 60.0 / time_interval
Another way would be divide 60 by float(time_interval)
Note this sample interaction:
In [7]: x = 31
In [8]: 60 / x
Out[8]: 1
In [9]: 60.0 / x
Out[9]: 1.935483870967742
Sharth meant to say: from __future__ import python
Example:
>>> from __future__ import division
>>> 4/3
1.3333333333333333
>>>