Using the inverse sec function in Python - python

I am creating a program that calculates the optimum angles to fire a projectile from a range of heights and a set initial velocity. Within the final equation I need to utilise, there is an inverse sec function present that is causing some troubles.
I have imported math and attempted to use asec(whatever) however it seems math can not calculate inverse sec functions? I also understand that sec(x) = 1/cos(x) but when I sub 1/cos(x) into the equation instead and algebraically solve for x it becomes a non real result :/.
The code I have is as follows:
print("This program calculates the optimum angles to launch a projectile from a given range of heights and a initial speed.")
x = input("Input file name containing list of heights (m): ")
f = open(x, "r")
for line in f:
heights = line
print("the heights you have selected are : ", heights)
f.close()
speed = float(input("Input your initial speed (m/s): "))
print("The initial speed you have selected is : ", speed)
ran0 = speed*speed/9.8
print(ran0)
f = open(x, "r")
for line in f:
heights = (line)
import math
angle = (math.asec(1+(ran0/float(heights))))/2
print(angle)
f.close()
So my main question is, is there any way to find the inverse sec of anything in python without installing and importing something else?
I realise this may be more of a math based problem than a coding problem however any help is appreciated :).

Let's say we're looking for real number x whose arcsecant is angle θ. Then we have:
θ = arcsec(x)
sec(θ) = x
1 / cos(θ) = x
cos(θ) = 1 / x
θ = arccos(1/x)
So with this reasoning, you can write your arcsecant function as:
from math import acos
def asec(x):
return acos(1/x)

"I also understand that sec(x) = 1/cos(x) but when I sub 1/cos(x) ..." Do you have to use sec or asec ?
Because sec(x)= 1/cos(x) and asec(x) = acos(1/x). Be careful the notation ^-1 is ambiguous, cos^-1(x) = acos(x) is different of [cos(x)]^-1.
angle = (math.asec(1+(ran0/float(heights))))/2
asec is not defined from -1 to 1
If you have a height lower than zero, and so the result of (ran0/float(heights)) is between -2 and 0, your angle will be non real.
I don't really know if this is what you asked for, but I hope it helps.

If math is OK for you to import, then you can use:
import math
def asec(x):
if x == 0:
return 1j * math.inf
else:
return math.acos(1 / x)
For some other ways of of re-writing asec(x), feast your eyes on the relevant Wikipedia article.
Alternatively, you could use Taylor series expansions, which always come in polynomial form, so, although that is only an approximation in a neighborhood of a given point, it would not require math.
For asec(x), its Taylor expansion in a neighborhood of ±∞ (also known as Laurent series) is given by (without using math):
def asec_taylor(x, pi=3.14159265):
if x == 0:
return 1j * float('inf')
else:
return pi / 2 - 1 / x - 1 / (6 * x ** 3) - 3 / (40 * x ** 5)
You can quickly check that the farther you are from 0, the better the approximation holds:
for x in range(-10, 10):
print(x, asec(x), asec_taylor(x))
-10 1.6709637479564565 1.670963741666667
-9 1.6821373411358604 1.6821373299281108
-8 1.696124157962962 1.6961241346516926
-7 1.714143895700262 1.7141438389326868
-6 1.7382444060145859 1.7382442416666668
-5 1.7721542475852274 1.7721536583333335
-4 1.8234765819369754 1.823473733854167
-3 1.9106332362490186 1.910611139814815
-2 2.0943951023931957 2.0939734083333335
-1 3.141592653589793 2.8124629916666666
0 (nan+infj) (nan+infj)
1 0 0.32912965833333346
2 1.0471975511965979 1.0476192416666668
3 1.2309594173407747 1.2309815101851853
4 1.318116071652818 1.3181189161458333
5 1.369438406004566 1.3694389916666667
6 1.4033482475752073 1.4033484083333334
7 1.4274487578895312 1.4274488110673134
8 1.4454684956268313 1.4454685153483076
9 1.4594553124539327 1.4594553200718894

If you can try of inverse of sec then it will be same as
>>>from mpmath import *
>>> asec(-1)
mpf('3.1415926535897931')
Here are the link in where you can better understand - [http://omz-software.com/pythonista/sympy/modules/mpmath/functions/trigonometric.html]

Related

issue with converting rate equation to python code

I am trying to convert these rate equations to python code, I have made I lot of research but can't seem to get any clear path to follow to achieve this, please any help will be appreciated
This is a newly updated code....i wrote using the quide from Tom10.....please what do you think?
import numpy as np
# import numpy as sum # not necessary, just for convenience, and replaces the builtin
# set N_core value
N_CORE = 0
# set the initial conditions appropriately (you need to set these correctly)
N = np.ones(8)
r = np.ones((8, 8))
dN = np.zeros(8) # the value here is not important for your equations
# set constant for equation 1
R_P1abs37 = 20
F_P1 = 20
R_P1abs47 = 40
W_3317 = 1.0
# set constant for equation 2
W_6142 = 90
W_5362 = 80
# Set you constants appropriately for equation 3
R_P2abs35 = 30
F_P2 = 40
R_L2se34 = 50
F_L2 = 90
# equation 4 constants
W_2214 = 20
#equation 5 constants
R_P1abs13 = 30
R_L2se32 = 20
F_L1 = 10
# equation 1 formular
dN[7] =sum(r[7,:]*N[7]) + (R_P1abs37*F_P1) + (R_P1abs47*F_P1) + (W_3317*N[3]**2)
# equation 2 formular
dN[6] = (r[7,6]*N[7]) - sum(r[6,:]*N[6]) - (W_6142*N[6]*N[1]) + (W_5362*N[5]*N[3])
#equation 3 formular
dN[5] = sum(r[:,5]*N) - sum(r[5,:]*N[5]) + R_P2abs35*F_P2 - R_L2se34*F_L2 - W_5362*N[5]*N[3]
# equation 4 formular
dN[4] = sum(r[:,4]*N) - sum(r[4,:]*N[4]) - (R_P1abs47*F_P1) + (R_L2se34*F_L2) + (W_2214*N[2]**2)+ (W_6142*N[6]*N[1])
#equation 5 formular
dN[3] = sum(r[:,3]*N) - sum(r[3,:]*N[3]) + (R_P1abs13*F_P1) - (R_P1abs37*F_P1) - (R_P2abs35*F_P2)
-(R_L2se32*F_L1) - ((2*W_3317)*N[3]**2) - (W_5362*N[5]*N[3])
#equation 6 formular
dN[2] = sum(r[:,2]*N) - (r[2,1]*N[2]) + (R_L2se32*F_L1) - ((2*W_2214)*N[2]**2) + (W_6142*N[6]*N[1])+(W_5362*N[5]*N[3])
#equation 7 formular
dN[1] = sum(r[:,1] * N) - (R_P1abs13*F_P1) + (W_2214*N[2]**2) + (W_3317+N[3]**2) - (W_6142+N[6]*N[1])
#equation for N CORE
N_CORE = sum(dN)
print(N_CORE)
Here is list of relevant issues based on your question and comments:
Usually if the summation is over i, then everything without an i subscript is constant for that sum. (Mathematically these constant terms can just be brought out of the sum; so the first equation is a bit odd where the N_7 could be moved out of the sum but I think they're keeping it in to show the symmetry with the other equations which all have an r*N term).
The capitol sigma symbol (Σ) means you need to do a sum, which you can do in a loop, but both Python list and numpy have a sum function. Numpy has the additional advantage that multiplication is interpreted as multiplication of the individual elements, making the expression easier. So for a[0]*[b0] + a[1]*b[1] + a[2]*b[2] and numpy arrays is simply sum(a*b) and for Python lists it's sum([a[i]*b[i] for in range(len(a))]
Therefore using numpy, the setup and your third equation would look like:
import numpy as np
import numpy.sum as sum # not necessary, just for convenience, and replaces the builtin
# set the initial conditions appropriately (you need to set these correctly)
N = np.ones(7, dtype=np.float)
# r seems to be a coupling matrix, and should be set according to your system
r = np.ones((7, 7), dtype = np.float)
# the values for dN are not important for your equations because dN only appears on the left side of the equations, so we just make a place to store the results
dN = np.zeros(7, dtype=np.float)
# Set you constants appropriate.y
R_P2abs35 = 1.0
F_P2 = 1.0
R_L2se34 = 1.0
F_L2 = 1.0
W_5362 = 1.0
dN[5] = sum(r[:,5]*N) - sum(r[5,:]*N[5]) + R_P2abs35*F_P2 - R_L2se34*F_L2 - W_5362*N[5]*N[3]
Note that although the expressions in the sums look similar, the first is essentially a dot product between two vectors and the second is a scalar times a vector so N[5] could be taken out of the sum (but I left it there to match the equation).
Final note: I see you're new to S.O. so I thought it would be helpful if I answered this question for you. In the future, please show some attempt at the code -- it really helps a lot.

Python: Calculating positive root of a quadratic equation

I am learning the Python tutorial on MIT, and I'm having a problem with one of the exercises. The exercise is,
Use the IPython prompt to calculate:
Positive root of the following equation: 34x2 + 68x - 510 = 0 Recall:
given ax2 + bx + c = 0 , then x = (-b +sqrt(b*b - 4ac))/(2*a)
I have entered
(-68)+(math.sqrt((68**2)-(4*34*510)))
in the iprompt, and I'm getting
Traceback (most recent call last):
File "", line 1, in
(-68)+(math.sqrt((68**2)-(434510)))
ValueError: math domain error
On calculating individually, I found that the value inside the square root is negative. Should I be adding some additional functions to enable negative root calculation, or is there something else that is wrong with my statement?
Can someone help me out?
Note: The solutions on the course page suggest making
(b**2-4ac)
positive before calculating the root. Will this not be mathematically inaccurate?
I am taking the same course, I did this way and got the right answers. Write the equation like this:
(-68+((68**2)-4*34*(-510))**0.5)/(2*34)
That will give you the 1st solution, just change the sign of plus to minus and you get the 2nd solution, as:
(-68-((68**2)-4*34*(-510))**0.5)/(2*34)
Check the photo I have attached, it is a screenshot of the solutions.
Screenshot of Spyder solving equation 34x^2+68x-510
Let f(x) = ax² + bx + c. If you want to solve f(x) = 0 in the field of real numbers, then you need to take care of the discriminant of f defined to be b² - 4ac. If the latter is negative, you do not have real solutions (and to have solutions you need to consider f as a complex polynomial, meaning that you want to find a solution to f(x) = 0 in the field of complex numbers).
Now, for your problem, it appears that you have a sign problem. The coefficient c is equal to -510 and not 510. Thus, 68² - 4*34*510 should be 68² - 4*34*(-510) = 68² + 4 * 34 * 510.
if f(x) = ax^2 + bx + c then its positive root will be
( -b + sqrt (b^2 - 4ac)) / 2a
According to your Question f(x) = 34x^2 + 68x - 510 = 0
So +ve root will be => ( -68 + sqrt (68^2 - 4*34*(-510)) ) / (2*34) = 3
In python code will be like -
from math import sqrt
print((-68 + sqrt(68**2 - 4*34*(-510)))/(2*34))
But what you did wrong is, you have taken co-efficient of 'C' is 510.
Instead It should be (-510).
I'm doing the course as well.
The question is from "getting started", so it shouldn't be hard.
And it should be related to the course material.
Therefore, here is what I have:
IDLE 1.2.4
>>> import math
>>> a=34
>>> b=68
>>> c=-510
>>> d = ( -b + math.sqrt ( b*b - 4*a*c))/(2 * a)
>>> print d
3.0

calculate equivalent width using python code

I have this Fortran program for compute equivalent width of spectral lines
i hope to find help for write python code to do same algorithm (input file contain tow column wavelength and flux)
PARAMETER (N=195) ! N is the number of data
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
DIMENSION X(N),Y(N)
OPEN(1,FILE='halpha.dat')
DO 10 I=1,N
READ(1,*)X(I),Y(I)
WRITE(*,*)X(I),Y(I)
10 CONTINUE
CALL WIDTH(X,Y,N,SUM)
WRITE(*,*)SUM
END
c-----------------------------------------
SUBROUTINE WIDTH(X,Y,N,SUM)
PARAMETER (NBOD=20000)
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
DIMENSION X(NBOD),Y(NBOD)
SUM=0.D0
DO I=2,N
SUM=SUM+(X(I-1)-X(I))*((1.-Y(I-1))+(1.-Y(I)))
C WRITE(*,*)SUM
END DO
SUM=0.5*dabs(SUM)
RETURN
END
Here's a fairly literal translation:
def main():
N = 195 # number of data pairs
x, y = [0 for i in xrange(N)], [0 for i in xrange(N)]
with open('halpha.dat') as f:
for i in xrange(N):
x[i], y[i] = map(float, f.readline().split())
print x[i], y[i]
sum = width(x, y, N)
print sum
def width(x, y, N):
sum = 0.0
for i in xrange(1, N):
sum = sum + (x[i-1] - x[i]) * ((1. - y[i-1]) + (1. - y[i]))
sum = 0.5*abs(sum)
return sum
main()
However this would be a more idiomatic translation:
from math import fsum # more accurate floating point sum of a series of terms
def main():
with open('halpha.dat') as f: # Read file into a list of tuples.
pairs = [tuple(float(word) for word in line.split()) for line in f]
for pair in pairs:
print('{}, {}'.format(*pair))
print('{}'.format(width(pairs)))
def width(pairs):
def term(prev, curr):
return (prev[0] - curr[0]) * ((1. - prev[1]) + (1. - curr[1]))
return 0.5 * abs(fsum(term(*pairs[i-1:i+1]) for i in range(1, len(pairs))))
main()
I would suggest that a more natural way to do this in Python is to focus on the properties of the spectrum itself, and use your parameters in astropy's specutils.
In particular equivalent_width details are here. For more general info on
specutils, specutils.analysis and its packages follow these links:
specutils top level
and
specutils.analysis
To use this package you need to create a Spectrum1D object, the first component of which will be your wavelength axis and the second will be the flux. You can find details of how to create a Spectrum1D object by following the link in the analysis page (at the end of the third line of first paragraph).
It's a very powerful approach and has been developed by astronomers for astronomers.

Leibniz formula for π - Is this any good? (Python)

I'm doing an exercise that asks for a function that approximates the value of pi using Leibniz' formula. These are the explanations on Wikipedia:
Logical thinking comes to me easily, but I wasn't given much of a formal education in maths, so I'm a bit lost as to what the leftmost symbols in the second one represent. I tried to make the code pi = ( (-1)**n / (2*n + 1) ) * 4, but that returned 1.9999990000005e-06 instead of 3.14159..., so I used an accumulator pattern instead (since the chapter of the guide that this was in mentions them as well) and it worked fine. However, I can't help thinking that it's somewhat contrived and there's probably a better way to do it, given Python's focus on simplicity and making programmes as short as possible. This is the full code:
def myPi(n):
denominator = 1
addto = 1
for i in range(n):
denominator = denominator + 2
addto = addto - (1/denominator)
denominator = denominator + 2
addto = addto + (1/denominator)
pi = addto * 4
return(pi)
print(myPi(1000000))
Does anyone know a better function?
The Leibniz formula translates directly into Python with no muss or fuss:
>>> steps = 1000000
>>> sum((-1.0)**n / (2.0*n+1.0) for n in reversed(range(steps))) * 4
3.1415916535897934
The capital sigma here is sigma notation. It is notation used to represent a summation in concise form.
So your sum is actually an infinite sum. The first term, for n=0, is:
(-1)**0/(2*0+1)
This is added to
(-1)**1/(2*1+1)
and then to
(-1)**2/(2*2+1)
and so on for ever. The summation is what is known mathematically as a convergent sum.
In Python you would write it like this:
def estimate_pi(terms):
result = 0.0
for n in range(terms):
result += (-1.0)**n/(2.0*n+1.0)
return 4*result
If you wanted to optimise a little, you can avoid the exponentiation.
def estimate_pi(terms):
result = 0.0
sign = 1.0
for n in range(terms):
result += sign/(2.0*n+1.0)
sign = -sign
return 4*result
....
>>> estimate_pi(100)
3.1315929035585537
>>> estimate_pi(1000)
3.140592653839794
Using pure Python you can do something like:
def term(n):
return ( (-1.)**n / (2.*n + 1.) )*4.
def pi(nterms):
return sum(map(term,range(nterms)))
and then calculate pi with the number of terms you need to reach a given precision:
pi(100)
# 3.13159290356
pi(1000)
# 3.14059265384
The following version uses Ramanujan's formula as outlined in this SO post - it uses a relation between pi and the "monster group", as discussed in this article.
import math
def Pi(x):
Pi = 0
Add = 0
for i in range(x):
Add =(math.factorial(4*i) * (1103 + 26390*i))/(((math.factorial(i))**4)*(396**(4*i)))
Pi = Pi + (((math.sqrt(8))/(9801))*Add)
Pi = 1/Pi
print(Pi)
Pi(100)
This was my approach:
def estPi(terms):
outPut = 0.0
for i in range (1, (2 * terms), 4):
outPut = (outPut + (1/i) - (1/(i+2)))
return 4 * outPut
I take in the number of terms the user wants, then in the for loop I double it to account for only using odds.
at 100 terms I get 3.1315929035585537
at 1000 terms I get 3.140592653839794
at 10000 terms I get 3.1414926535900345
at 100000 terms I get 3.1415826535897198
at 1000000 terms I get 3.1415916535897743
at 10000000 terms I get 3.1415925535897915
at 100000000 terms I get 3.141592643589326
at 1000000000 terms I get 3.1415926525880504
Actual Pi is 3.1415926535897932
Got to love a convergent series.
def myPi(iters):
pi = 0
sign = 1
denominator = 1
for i in range(iters):
pi = pi + (sign/denominator)
# alternating between negative and positive
sign = sign * -1
denominator = denominator + 2
pi = pi * 4.0
return pi
pi_approx = myPi(10000)
print(pi_approx)
old thread, but i wanted to stuff around with this and coincidentally i came up with pretty much the same as user3220980
# gregory-leibnitz
# pi acurate to 8 dp in around 80 sec
# pi to 5 dp in .06 seconds
import time
start_time = time.time()
pi = 4 # start at 4
times = 100000000
for i in range(3,times,4):
pi -= (4/i) + (4/(i + 2))
print(pi)
print("{} seconds".format(time.time() - start_time))

Project Euler #45: How is my logic wrong?

From Project Euler, problem 45:
Triangle, pentagonal, and hexagonal numbers are generated by the following formulae:
Triangle T_(n)=n(n+1)/2 1, 3, 6, 10, 15, ...
Pentagonal P_(n)=n(3n−1)/2 1, 5, 12, 22, 35, ...
Hexagonal H_(n)=n(2n−1) 1, 6, 15, 28, 45, ...
It can be verified that T_(285) = P_(165) = H_(143) = 40755.
Find the next triangle number that is also pentagonal and hexagonal.
[ http://projecteuler.net/problem=45 ]
Now to solve them I took three variables and equated the equations to A.
n(n + 1)/2 = a(3a - 1)/2 = b(2b - 1) = A
A = number at which the threee function coincide for values of n, a, b
Resultant we get 3 equations with n and A. Solving with quarditic formula, we get 3 equations.
(-1 + sqrt(1 + 8*A ) )/2
( 1 + sqrt(1 + 24*A) )/6
( 1 + sqrt(1 + 8*A ) )/4
So my logic is to test for values of A at which the three equation give a natural +ve value. So far it works correct for number 40755 but fails to find the next one upto 10 million.
(Edit): Here is my code in python
from math import *
i=10000000
while(1):
i = i + 1
if(((-1+sqrt(1+8*i))/2).is_integer()):
if(((1+sqrt(1+24*i))/6).is_integer()):
if(((1+sqrt(1+8*i))/4).is_integer()):
print i
break
How is my logic wrong? (Apologies for a bit of maths involved. :) )
Given that:
all hexagonals are also triangulars
heapq.merge is quite handy for the task at hand (efficient and saves code)
then this:
import heapq
def hexagonals():
"Simplified generation of hexagonals"
n= 1
dn= 5
while 1:
yield n
n+= dn
dn+= 4
def pentagonals():
n= 1
dn= 4
while 1:
yield n
n+= dn
dn+= 3
def main():
last_n= 0
for n in heapq.merge(hexagonals(), pentagonals()):
if n == last_n:
print n
last_n= n
main()
produces 1, 40755 and the other number you're seeking in almost no time, and a few seconds later a 14-digit number. Just stop the program when you think you burned enough electricity.
In case you want to avoid “opaque” libraries, use the following main (essentially the same algorithm, only spelled out):
def main():
hexagonal= hexagonals()
pentagonal= pentagonals()
h= next(hexagonal)
p= next(pentagonal)
while 1:
while p < h:
p= next(pentagonal)
if p == h:
print p
h= next(hexagonal)
Times look similar, but I didn't bother to benchmark.
Your logic is not wrong, your program just takes a long time to run (by my estimate it should provide an answer in about an hour). I know the answer and tested your program by setting i to a value just below it. Your program then popped out the right answer at once.
Heed the advice of ypercube.
simplest way to implement is to make 3 generators for each sequence and route them in
heapq.merge
and then if you find 3 same consecitive keys you got solution
Simplest way to find this is usnig
itertools.groupby

Categories