I want to write a function that when I input the dimensions of a truncated cone (a cup) and an amount of liquid in litres returns how many of these cups can be filled up with the amount of liquid.I understand that 1L = 1000 cm^3 but I do not understand how I would incorporate it into my code to return the outcome I expect
def number_of_cups(bottom_radius, top_radius, height, litres_of_liquid):
volume = math.pi / 3 * height * (bottom_radius**2 + top_radius * bottom_radius + top_radius**2)
return int(filled_cup)
This is as far as I have got, I know I am close but I don't understand how to word my conversion,
That depends on the unit in which bottom_radius, top_radius and height are given. If we assume that those length are given in cm then
def number_of_cups(bottom_radius, top_radius, height, litres_of_liquid):
volume = math.pi / 3 * height * (bottom_radius**2 + top_radius * bottom_radius + top_radius**2)
return int( litres_of_liquid * 1000 / volume )
litres_of_liquid * 1000 is litres converted to cm^3. The int() could be replaced by math.floor() in case the number of completely full cups is intended, math.ceil() will give the number of full or partially filled cups.
Finally, there is a nice package magnitude which encapsulates a physical quantity. You could use this package in case the user wants to specify different length units.
The Formula stated by the OP is correct.
OK, just want to point out, your volume calculation seems wrong.
def number_of_cups(bottom_radius, top_radius, height, litres_of_liquid):
volume = 4 * math.pi * height * (bottom_radius**2 + top_radius**2)/2
filled_cup = 1000 * litres_of_liquid / volume
return int(filled_cup)
And in case you did't know, division is different in Python2 and Python3.
Python 2
>>> 1/2
0
Python 3
>>> 1/2
0.5
>>> 1//2
0
Throwing my own anwer to the pile:
#!/usr/bin/python2
import math
# nothing about units here , but let's say it's cm
def cup_vol(b_rad=3, t_rad=4, h=5):
vol = math.pi/3 * (b_rad**2 + t_rad + b_rad + t_rad**2) * h
return vol
def n_cups(liquid_amount, whole_cups=True): # nothing about units here
# liquid amount is Liter then first convert it to CM^3
liquid_amount = liquid_amount*1000
# this yields an int
if whole_cups:
return int(liquid_amount/cup_vol())
# else, return a real number with fraction
return liquid_amount/cup_vol()
if __name__ == '__main__':
print "4L fill %f cups" % n_cups(4)
print "4L fill %f cups (real)" % n_cups(4, whole_cups=False)
Running the above script yields:
4L fill 23.000000 cups
4L fill 23.873241 cups (real)
Related
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]
I'm trying to calculate the average weighted interest rates of loans in Python 2.7.
I started out with floats, and that was problematic. Given these inputs (Loan #1 $20,000 6.80%; Loan #2 $10,000 7.90%; Loan #3 $10,000 5.41%) the correct result is 6.7275. Using Decimal, my code outputs that.
However, I am supposed to take that number and round up to the nearest 1/8% and display the result as 6.75 instead. When I use format to round to two places, I get 6.73. While that is what I would expect, is does not meet the scope of what this function should do.
from decimal import Decimal
def weightedAvgFixedArgs(r1,r2,r3,b1,b2,b3):
rates = [Decimal(r1),Decimal(r2),Decimal(r3)]
balances = [Decimal(b1),Decimal(b2),Decimal(b3)]
a = Decimal(b1) * Decimal(r1)
b = Decimal(b2) * Decimal(r2)
c = Decimal(b3) * Decimal(r3)
perLoanWghtFctr = a + b + c
totalLoanAmt = sum(balances)
intRate = (perLoanWghtFctr / totalLoanAmt) * 100
return format(intRate, '.2f')
Edit: Joachim Isaksson's suggestion provides the output I requested with the inputs I provided. I haven't tested this extensively in my particular use-case, but it correctly answers the question I asked.
# return format(intRate, '.2f')
z = intRate * 8
y = format(z, '.0f')
x = Decimal(y) / Decimal(8)
return x
To round up to the nearest 1/8%:
import math
>>> math.ceil(.73 * 8) / 8
0.75
>>> math.ceil(.76 * 8) / 8
0.875
If you're specifically told to round up, you should use ceiling.
import math
x = 6.7275
x = math.ceil(x * 8)/8 # x == 6.75
Multiply 8, round or truncate as you want, then divide by 8, here is the sample code:
for i in range(0,10):
v = i/10.0
v = round(v*8) / 8.0
print i/10.0, v
Run it you will get:
0.0 0.0
0.1 0.125
0.2 0.25
0.3 0.25
0.4 0.375
0.5 0.5
0.6 0.625
0.7 0.75
0.8 0.75
0.9 0.875
When calculating the Weighted Average Interest rate, you will have to ROUND UP.
Some source(s) about calculation related to interest rates:
Tutorial: Calculating the Weighted Average Interest Rate
Weighted Average Interest Rate Calculator
Interest Rates on Federal Consolidation Loans
Federal Student Financial Aid Handbook
I think this is the best way to do what you are asking for:
import math
x = 6.73
math.ceil(x / (1/8)) * (1/8)
I personally do not have a clear (mathematical) explanation of why doing first the multiplication and then later the division also works. Or doing it with value 8 instead of 1/8. The example below also seems to work:
math.ceil(x * (8)) / 8
Both works. In the first example, you are able to use it as the given value, which is (1/8), and at the second example you are able to use ut as a whole number, in this case, it's 8.
If you want to round to just the nearest 1/8% (and not round up to the nearest 1/8%, as it's supposed to be), that is a different case.
Is there a proper way to handle percentages in Python?
For example, how to handle the value 0.01 and make it displayed as 1%
You can also use str.format()
percentage = 0.01
print "{0:.0f}%".format(percentage * 100)
1%
percentage = 0.0142
print "{0:.0f}%".format(percentage * 100)
1%
percentage = 0.0142
print "{0:.1f}%".format(percentage * 100)
1.4%
Multiply by a hundred then convert to int
>>> int(0.01 * 100)
1
As a function
def dec_to_pct(i):
return int(i*100)
>>> dec_to_pct(0.01)
1
>>> dec_to_pct(0.07)
7
>>> dec_to_pct(0.42)
42
Note
If you'd like to preserve remaining decimals, just leave off the conversion to int, e.g.
>>> 0.4273 * 100
42.73 # percent
def pi():
prompt=">>> "
print "\nWARNING: Pi may take some time to be calculated and may not always be correct beyond 100 digits."
print "\nShow Pi to what digit?"
n=raw_input(prompt)
from decimal import Decimal, localcontext
with localcontext() as ctx:
ctx.prec = 10000
pi = Decimal(0)
for k in range(350):
pi += (Decimal(4)/(Decimal(8)*k+1) - Decimal(2)/(Decimal(8)*k+4) - Decimal(1)/(Decimal(8)*k+5) - Decimal(1)/(Decimal(8)*k+6)) / Decimal(16)**k
print pi[:int(n)]
pi()
Traceback (most recent call last):
File "/Users/patrickcook/Documents/Pi", line 13, in <module>
pi()
File "/Users/patrickcook/Documents/Pi", line 12, in pi
print pi[:int(n)]
TypeError: 'Decimal' object has no attribute '__getitem__'
If you'd like a faster pi algorithm, try this one. I've never used the Decimal module before; I normally use mpmath for arbitrary precision calculations, which comes with lots of functions, and built-in "constants" for pi and e. But I guess Decimal is handy because it's a standard module.
''' The Salamin / Brent / Gauss Arithmetic-Geometric Mean pi formula.
Let A[0] = 1, B[0] = 1/Sqrt(2)
Then iterate from 1 to 'n'.
A[n] = (A[n-1] + B[n-1])/2
B[n] = Sqrt(A[n-1]*B[n-1])
C[n] = (A[n-1]-B[n-1])/2
PI[n] = 4A[n+1]^2 / (1-(Sum (for j=1 to n; 2^(j+1))*C[j]^2))
See http://stackoverflow.com/q/26477866/4014959
Written by PM 2Ring 2008.10.19
Converted to use Decimal 2014.10.21
Converted to Python 3 2018.07.17
'''
import sys
from decimal import Decimal as D, getcontext, ROUND_DOWN
def AGM_pi(m):
a, b = D(1), D(2).sqrt() / 2
s, k = D(0), D(4)
for i in range(m):
c = (a - b) / 2
a, b = (a + b) / 2, (a * b).sqrt()
s += k * c * c
#In case we want to see intermediate results
#if False:
#pi = 4 * a * a / (1 - s)
#print("%2d:\n%s\n" % (i, pi))
k *= 2
return 4 * a * a / (1 - s)
def main():
prec = int(sys.argv[1]) if len(sys.argv) > 1 else 50
#Add 1 for the digit before the decimal point,
#plus a few more to compensate for rounding errors.
#delta == 7 handles the Feynman point, which has six 9s followed by an 8
delta = 3
prec += 1 + delta
ctx = getcontext()
ctx.prec = prec
#The precision of the AGM value doubles on every loop
pi = AGM_pi(prec.bit_length())
#Round down so all printed digits are (usually) correct
ctx.rounding = ROUND_DOWN
ctx.prec -= delta
print("pi ~=\n%s" % +pi)
if __name__ == '__main__':
main()
You are trying to treat pi as an array, when it is a Decimal. I think you are looking for quantize:https://docs.python.org/2/library/decimal.html
I got bored with how long the process it was taking (that 350-iteration loop is a killer), but the answer seems plain. A Decimal object is not subscriptable the way you have it.
You probably want to turn it into a string first and then process that to get the digits:
print str(pi)[:int(n)+1] # ignore decimal point in digit count.
You should also keep in mind that this truncates the value rather than rounding it. For example, with PI starting out as:
3.141592653589
(about as much as I can remember off the top of my head), truncating the string at five significant digits will give you 3.1415 rather than the more correct 3.1416.
A Decimal object can't be sliced to get the individual digits. However a string can, so convert it to a string first.
print str(pi)[:int(n)]
You may need to adjust n for the decimal point and desired digit range.
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))