1+ # Calculus Bisection Class Project
2+ # Author: Nicholas Assaderaghi (FlyN Nick)
3+ # Translated from TypeScript to Python (see https://github.com/FlyN-Nick/Bisection-Method-TypeScript).
4+
5+ import math
6+ #import sys
7+
8+ def convert (f , x : float ) -> float :
9+ """Returns the value of an expression given x."""
10+ if type (f ) is str :
11+ return eval (f )
12+ return f (x )
13+
14+ def bisection (f , min : float , max : float , maxIter = 100 , annoyingPrints = False ):
15+ """Bisection function: finds the root of a function within given range.
16+
17+ Things that may cause this to be unsuccessfull/error:
18+ #1: Root is not within given range.
19+ #2: Function changes signs more than once within given range.
20+ #3: The given minimum is greater than the given maximum.
21+ #4: There are x within given range where f(x) is undefined.
22+
23+ Parameters
24+ ----------
25+ f : str or function
26+ Function that is being evaluated.
27+ min : float
28+ The given lower bound of the possible range of the root
29+ max : float
30+ The given upper bound of the possible range of the root
31+ maxIter : int, optional
32+ The maximum number of iterations (default 1000)
33+ annoyingPrints : bool, optional
34+ Enables an annoying print statement every iteration (default False)
35+ """
36+
37+ print ('---------------------------------------------------------------' );
38+
39+ if min > max :
40+ print ('You seem to have mixed the min and max...' )
41+ return 'ERROR'
42+ elif min is max and convert (f , min ) == 0 :
43+ print ('Wow, the given min and max were the same and were the root. Kinda seems like this was on purpose...' )
44+ return min
45+ elif min is max :
46+ print ('Wow, the given min and max were the same but were not the root. Kinda seems like this was on purpose...' )
47+ return 'ERROR'
48+ elif convert (f , min ) == 0 :
49+ print ('Wow, the lower bound of the given range was the root. Kinda seems like this was on purpose...' )
50+ return min
51+ elif convert (f , max ) == 0 :
52+ print ('Wow, the upper bound of the given range was the root. Kinda seems like this was on purpose...' )
53+ return max
54+
55+ posSlope = True
56+ if convert (f , min ) > convert (f , (min + max / 2 )):
57+ posSlope = False
58+
59+ iter = 0
60+ while iter != maxIter :
61+ iter += 1
62+ guess = (min + max )/ 2
63+
64+ if (convert (f , guess ) < 0 and posSlope ) or (convert (f , guess ) > 0 and not posSlope ):
65+ if guess == min :
66+ print (f'Stopped at iteration #{ iter } .' )
67+ print (f'Root not found.\n Range: ({ min } , { max } ).' )
68+ return [min , max ]
69+ min = guess
70+ elif (convert (f , guess ) > 0 and posSlope ) or (convert (f , guess ) < 0 and not posSlope ):
71+ if guess == max :
72+ print (f'Stopped at iteration #{ iter } .' )
73+ print (f'Root not found.\n Range: ({ min } , { max } ).' )
74+ return [min , max ]
75+ max = guess
76+ else :
77+ print (f'Root: { guess } .\n Iterations it took: { iter } .' )
78+ return guess
79+ if annoyingPrints :
80+ print (f'Iteration #{ iter } :\n \t Current range: ({ min } , { max } )' )
81+
82+ print (f'Root not found (maximum iterations reached).\n Range: ({ min } , { max } ).' )
83+
84+ print (f'Remember, this algorithm will only work if:\n \t #1: The root is within the range.\n \t #2: The function changes sign once within the interval.' )
85+
86+ return [min , max ]
87+
88+ def testBisectionFunction ():
89+ """Just testing if everything generally works. This is not an in-depth test (does not test all error scenarios)."""
90+ print ('TESTING BISECTION FUNCTION!\n ' )
91+
92+ def linFunc (x : float ) -> float :
93+ return 2 * x - 19
94+
95+ linFuncString = '2*x-19'
96+ polyFunc = 'x**2+x-5'
97+ trigFuncOne = 'math.sin(1/x)'
98+ trigFuncTwo = 'math.sin(x)/x'
99+
100+ returnedVals = [
101+ bisection (linFunc , 9.5 , 9.5 ), # root is both given min and max
102+ bisection (linFunc , 5 , 5 ), # given min and max are the same, but not the root
103+ bisection (linFunc , 9.5 , 10 ), # root is the given min
104+ bisection (linFunc , 9 , 9.5 ), # root is the given max
105+ bisection (linFunc , - 100 , 0 ), # root not within range
106+ bisection (linFunc , 100 , - 100 ), # upper and lower switched
107+ bisection (linFuncString , - 100 , 100 ),
108+ bisection (polyFunc , 0 , 21 ),
109+ bisection (trigFuncOne , 0.212 , 0.637 , 100000 ),
110+ bisection (trigFuncTwo , 0.1 , 4.25 , 1000 )
111+ ]
112+
113+ print ('---------------------------------------------------------------' )
114+ print (f'\n Returned values from bisection function:\n [' );
115+
116+ length = len (returnedVals )
117+ i = 0
118+ #print(returnedVals)
119+ for returnedVal in returnedVals :
120+ i += 1
121+ if i != length :
122+ print (f'\t { returnedVal } ,' )
123+ else :
124+ print (f'\t { returnedVal } \n ]' )
125+
126+ if __name__ == '__main__' :
127+ testBisectionFunction ()
0 commit comments