I have to write a program of Maclaurin series ln(x+1) on Python.
I need to use input function for two values: x, n. Then check if the values are legal and calculates the Maclaurin approximation (of order n) of the expression ln (1 + 𝑥) around the point x.
*Maclaurin series ln(x+1)= sum of ((-1)^n/n)*x^n
I stacked in the end when I calculate to expression, that what I wrote (after all the checks before):
for i in range(n + 1):
if i <= 1:
continue
else:
x = x + (((-1) ** (i + 1)) * (x ** i) / i)
When I input the test I get a number but it's a wrong answer.
Please help me understand what is wrong in this code.
Mathematically, the Maclaurin series is a bit beyond me, but I'll try to help. Two things.
First, you're storing all the successive values in x, as you calculate them; that means that the term for n = 5 (i = 5) is using a value of x which isn't the original value of the parameter x, but which has the successive results of the four previous computations stored in it. What you need to do instead is something like:
total = 0
for each value:
this term = some function of x # the value of x does not change
total = total + this term
Second, why aren't you interested in the term when i (or n) is equal to 1? The condition
if i <= 1:
continue
skips out the case when i equals 1, which evaluates to -x.
That should fix it, as far as I can see.
You are modifying the value of x in each iteration of the loop. Add and then store the partial sums in another variable.
def maclaurin_ln(x, n):
mac_sum = 0
for i in range(1, n + 1):
mac_sum += (((-1) ** (i + 1)) * (x ** i) / i)
return mac_sum
You can test this with the built-in function log1p to see how close they can get.
For ln(2) for different n,
from tabulate import tabulate
res = []
for n in [1, 10, 100, 1000, 10000]:
p = math.log1p(1)
q = maclaurin_ln(1, n)
res.append([1, n, p, q, q-p])
tabulate(res, headers=["x", "n", "log1p", "maclaurin_ln", "maclaurin_ln-log1p"])
x n log1p maclaurin_ln maclaurin_ln-log1p
--- ----- -------- -------------- --------------------
1 1 0.693147 1 0.306853
1 10 0.693147 0.645635 -0.0475123
1 100 0.693147 0.688172 -0.004975
1 1000 0.693147 0.692647 -0.00049975
1 10000 0.693147 0.693097 -4.99975e-05
For different x,
res = []
for x in range(10):
p = math.log1p(x/10)
q = maclaurin_ln(x/10, 100)
res.append([x/10, 1000, p, q, q-p])
tabulate(res, headers=["x", "n", "log1p", "maclaurin_ln", "maclaurin_ln-log1p"])
x n log1p maclaurin_ln maclaurin_ln-log1p
--- ---- --------- -------------- --------------------
0 1000 0 0 0
0.1 1000 0.0953102 0.0953102 1.38778e-17
0.2 1000 0.182322 0.182322 2.77556e-17
0.3 1000 0.262364 0.262364 -1.11022e-16
0.4 1000 0.336472 0.336472 0
0.5 1000 0.405465 0.405465 -1.11022e-16
0.6 1000 0.470004 0.470004 5.55112e-17
0.7 1000 0.530628 0.530628 -4.44089e-16
0.8 1000 0.587787 0.587787 -9.00613e-13
0.9 1000 0.641854 0.641854 -1.25155e-07
Related
Creating evenly spaced numbers on a log scale (a geometric progression) can easily be done for a given base and number of elements if the starting and final values of the sequence are known, e.g., with numpy.logspace and numpy.geomspace. Now assume I want to define the geometric progression the other way around, i.e., based on the properties of the resulting geometric series. If I know the sum of the series as well as the first and last element of the progression, can I compute the quotient and number of elements?
For instance, assume the first and last elements of the progression are and and the sum of the series should be equal to . I know from trial and error that it works out for n=9 and r≈1.404, but how could these values be computed?
You have enough information to solve it:
Sum of series = a + a*r + a*(r^2) ... + a*(r^(n-1))
= a*((r^n)-1)/(r-1)
= a*((last element * r) - 1)/(r-1)
Given the sum of series, a, and the last element, you can use the above equation to find the value of r.
Plugging in values for the given example:
50 = 1 * ((15*r)-1) / (r-1)
50r - 50 = 15r - 1
35r = 49
r = 1.4
Then, using sum of series = a*((r^n)-1)/(r-1):
50 = 1*((1.4^n)-1)(1.4-1)
21 = 1.4^n
n = log(21)/log(1.4) = 9.04
You can approximate n and recalculate r if n isn't an integer.
We have to reconstruct geometric progesssion, i.e. obtain a, q, m (here ^ means raise into power):
a, a * q, a * q^2, ..., a * q^(m - 1)
if we know first, last, total:
first = a # first item
last = a * q^(m - 1) # last item
total = a * (q^m - 1) / (q - 1) # sum
Solving these equation we can find
a = first
q = (total - first) / (total - last)
m = log(last / a) / log(q)
if you want to get number of items n, note that n == m + 1
Code:
import math
...
def Solve(first, last, total):
a = first
q = (total - first) / (total - last)
n = math.log(last / a) / math.log(q) + 1
return (a, q, n);
Fiddle
If you put your data (1, 15, 50) you'll get the solution
a = 1
q = 1.4
n = 9.04836151801382 # not integer
since n is not an integer you, probably want to adjust; let last == 15 be exact, when total can vary. In this case q = (last / first) ^ (1 / (n - 1)) and total = first * (q ^ n - 1) / (q - 1)
a = 1
q = 1.402850552006674
n = 9
total = 49.752 # now n is integer, but total <> 50
You have to solve the following two equations for r and n:
a:= An / Ao = r^(n - 1)
and
s:= Sn / Ao = (r^n - 1) / (r - 1)
You can eliminate n by
s = (r a - 1) / (r - 1)
and solve for r. Then n follows by log(a) / log(r) + 1.
In your case, from s = 50 and a = 15, we obtain r = 7/5 = 1.4 and n = 9.048...
It makes sense to round n to 9, but then r^8 = 15 (r ~ 1.40285) and r = 1.4 are not quite compatible.
I'm building a Genetic Algorithm to maximize this function: x^5 - 10x^3 + 30x - y^2 + 21y.
The code must be in binary and the bounds for x and y are [-2.5, 2.5]. To generate the initial population I made a 16 bit string for both x and y where:
The first bit represents the signal [0 or 1]
The the second and third bit represents the integer part [00, 01 or 10]
The rest represents the float part
This is the function that generates the initial population:
def generate_population(n_pop):
population = list()
for _ in range(n_pop):
aux = list()
for _ in range(2):
signal = bin(randint(0, 1))[2:]
int_part = bin(randint(0, 2))[2:].zfill(2)
float_part = bin(randint(0, 5000))[2:].zfill(13)
aux.append((signal+int_part+float_part))
population.append(aux)
return population
I also made a function that returns the binary number into float:
def convert_float(individual):
float_num = list()
for i in range(2):
signal = int(individual[i][0])
int_part = int(individual[i][1:3], 2)
float_part = int(individual[i][3:], 2) * (10 ** -4)
value = round(int_part + float_part, 4)
if value > 2.5:
value = 2.5
if signal == 1:
value = value * (-1)
float_num.append(value)
return float_num
And lastly this function that calculate the fitness of each individual:
def get_fitness(individual):
x = individual[0]
y = individual[1]
return x ** 5 - 10 * x ** 3 + 30 * x - y ** 2 + 21 * y
This is my main function:
def ga(n_pop=10, n_iter=10):
population = generate_population(n_pop)
best_fitness_id, best_fitness = 0, get_fitness(convert_float(population[0]))
for i in range(n_iter):
float_population = [convert_float(x) for x in population]
fitness_population = [get_fitness(x) for x in float_population]
for j in range(n_pop):
if fitness_population[j] > best_fitness:
best_fitness_id, best_fitness = j, fitness_population[j]
print(f'--> NEW BEST FOUND AT GENERATION {i}:')
print(f'{float_population[j]} = {fitness_population[j]}')
selected_parents = rank_selection()
# childrens = list()
# childrens = childrens + population[best_fitness_id] # ELITE
After running the program I have something like this:
The population looks like: [['0000001100110111', '0000110111110101'], ['0010011111101110', '1000100101001001'], ...
The float population: [[0.0823, 0.3573], [1.203, -0.2377], ...
And the fitness values: [9.839066068044746, 16.15145434928624, ...
I need help to build the rank_selection() function, I've been stuck in this selection for 2 days. I know is something 1/N, 2/N etc and I've seen tons of examples in multiple languages but I could not apply any of them to this particular algorithm and it MUST be rank selecion.
I already know how to perform crossover and mutation.
Im tryng to convert this formula (WMA Moving Average) for loop in Python from Pinescript
but for i to x not exist. I tried for i in range(x) but seems dont return same result.
What exactly means to? Documentation of Pinescript said means from i to x but i dont find the equivalent in Python
pine_wma(x, y) =>
norm = 0.0
sum = 0.0
for i = 0 to y - 1
weight = (y - i) * y
norm := norm + weight
sum := sum + x[i] * weight
sum / norm
plot(pine_wma(close, 15))
Python Code:
import pandas as pd
dataframe = pd.read_csv('dataframe.csv')
def formula_wma(x, y):
list = []
norm = 0.0
sum = 0.0
i = 0
for i in range(y - 1):
weight = (y - i) * y
norm = norm + weight
sum = sum + x[i] * weight
_wma = sum / norm
list.append(_wma)
i += 1
return list
wma_slow = formula_wma(dataframe['close'],45)
dataframe['wma_slow'] = pd.Series(wma_slow, index=dataframe.index[:len(wma_slow)])
print(dataframe['wma_slow'].to_string())
Output:
0 317.328133
[Skipping lines]
39 317.589010
40 317.449259
41 317.421662
42 317.378052
43 317.328133
44 NaN
45 NaN
[Skipping Lines]
2999 NaN
3000 NaN
First of all, don't reassign built-in names!
sum is a built-in function that calculates the summation of a sequence of numbers. So is list, it is a class constructor.
For example:
sum(range(10)) returns 45.
The above is equivalent to:
numbers = (0,1,2,3,4,5,6,7,8,9)
s = 0
for i in numbers: s += i
Second, don't increment the variable you use for looping inside the loop, unless you have a good reason for it.
That i += 1 at the end of the loop has no effect whatsoever, for loop automatically reassigns the name to the next item in the sequence, in this case the next item is incremented by one, so i automatically gets incremented.
Further, if there is anything using i after that line, they will break.
Lastly, the reason you are not getting the same result, is Python uses zero-based indexing and range excludes the stop.
I don't know about pine script, but from what you have written, from x to y must include y.
For example 0 to 10 in pine script will give you 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
But using range(10):
print(list(range(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Why? Because there are exactly ten numbers in the range you specified.
In the first example, there are actually eleven numbers. If you know your math, the number of terms in an arithmetic sequence is the difference between the maximum term and the minimum term divided by the increment plus one.
So how to solve your problem?
Remove - 1 after y in range!
Fixed code:
import pandas as pd
dataframe = pd.read_csv('dataframe.csv')
def formula_wma(x, y):
lst = []
norm = 0.0
sum_ = 0.0
i = 0
for i in range(y):
weight = (y - i) * y
norm = norm + weight
sum_ = sum_ + x[i] * weight
_wma = sum_ / norm
lst.append(_wma)
return lst
wma_slow = formula_wma(dataframe['close'],45)
dataframe['wma_slow'] = pd.Series(wma_slow, index=dataframe.index[:len(wma_slow)])
print(dataframe['wma_slow'].to_string())
Need a better way to create a list of numbers, so that the run time is less. Or probably figure out a better approach to my problem.
I'm running a code to create a series of numbers based on 2 formulas. Starting from 1, the formulas create the following numbers. The idea is to return the number n from the list that is created at the end. Even tough the formulas create the same number in some cases, only unique values remain, and the list is sorted to match. I use a while loop to create the list, and I believe that reducing the number of repetitions can help with my problem, but I can't figure out a way to effectively reduce it, without ruining the purpose of my code.
def dbl_linear(n):
x = 1
y = 0
z = 0
i = 0
u = []
u.append(x)
while i <= n:
x = (u)[i]
y = 2 * x + 1
u.append(y)
z = 3 * x + 1
u.append(z)
i = i + 1
u.sort()
uFix = set(u)
uFix = list(uFix)
uFix.sort()
return uFix[n]
print(dbl_linear(50))
These are the expected results. Which I get, but it takes too long.
dbl_linear(10), 22)
dbl_linear(20), 57)
dbl_linear(30), 91)
dbl_linear(50), 175)
Your function can be considerably simplified to:
Code:
def dbl_linear(n):
u = [1]
for i in range(n):
x = u[i]
u.extend((2 * x + 1, 3 * x + 1))
return sorted(set(u))[n]
Test Code:
assert dbl_linear(10) == 22
assert dbl_linear(20) == 57
assert dbl_linear(30) == 91
assert dbl_linear(50) == 175
Write a function that accepts 3 numbers and calculates the average of the 3 numbers and raises the average to the second power (returns the average squared).
Write a loop that finds 3 random uniform numbers (0 to 1); sends the 3 numbers to the function and stops the loop when the value of the function is greater than 0.5625
I tried to figure out this 2 things but I am confused a little bit.
import random
a = random.random ()
b = random.random ()
c = random.random ()
def avenum(x1,x2,x3): # the average of the 3 numbers
z = (x1+x2+x3)/3.0
return z
y = avenum(a,b,c)
print 'the average of the 3 numbers = ',y
def avesec(x1,x2,x3): # the average of the second power
d = ((x1**2)+(x2**2)+(x3**2))/3.0
return d
y1 = avesec(a,b,c)
print 'the average of the second power = ',y1
The first question:
Write a function that accepts 3 numbers and calculates the average of the 3 numbers and raises the average to the second power (returns the average squared).
def square_of_average(x1, x2, x3):
z = (x1 + x2 + x3) / 3
return z ** 2 # This returns the square of the average
Your second question:
Write a loop that finds 3 random uniform numbers (0 to 1); sends the 3 numbers to the function and stops the loop when the value of the function is greater than 0.5625.
Assuming you want to write this in another function:
import random
def three_random_square_average():
z = 0 # initialize your answer
while(z <= 0.5625): # While the answer is less or equal than 0.5625...
# Generate three random numbers:
a, b, c = random.random(), random.random(), random.random()
# Assign the square of the average to your answer variable
z = square_of_average(a, b, c)
# When the loop exits, return the answer
return z
Another option:
import random
def three_random_squared_average():
while(True):
a, b, c = random.random(), random.random(), random.random()
z = square_of_average(a, b, c)
if(z > 0.5625):
break
return z
If you don't want a function:
import random
z = 0
while(z < 0.5625):
z = square_of_average(random.random(), random.random(), random.random())
print z
Firstly for 1) - you're raising the average to the second power... not each value. Otherwise you want the average of the second powers of the input values.
import random
a = random.random ()
b = random.random ()
c = random.random ()
def avenum1(x1,x2,x3): # the average of the 3 numbers
z = ((x1+x2+x3)/3.0)**2
return z
For 2): There are better ways but this is the most obvious.
def avenum1(x1,x2,x3): # the average of the 3 numbers
z = ((x1+x2+x3)/3.0)**2
return z
avg = 0:
while avg<0.5625:
a = random.random ()
b = random.random ()
c = random.random ()
avg = avenum1(a,b,c)
The better way:
avg = 0
while avg<0.5625:
list_ = [random.random() for i in range(3)]
avg = (sum(list_)/3.0)**2