1+ // Calculus Bisection Class Project
2+ // Author: Nicholas Assaderaghi (FlyN Nick)
3+ // Why did I write this in TypeScript: I felt like it :)
4+
5+ /**
6+ * Bisection function.
7+ * Finds the root of a function within given range.
8+ *
9+ * Things that may cause this to be unsuccessfull/error:
10+ * #1: Root is not within given range.
11+ * #2: Function changes signs more than once within given range.
12+ * #3: The given minimum is greater than the given maximum.
13+ * #4: There are x within given range where f(x) is undefined.
14+ *
15+ * @param {(x: number) => any } func - function you want to find the root of.
16+ * @param {number } givenMin - min of given range.
17+ * @param {number } givenMax - max of given range.
18+ * @param {bool } annoyingConsoleLogs - (optional) really annoying console log ever iteration.
19+ * @param {number } maxIter - (optional) max number of iterations
20+ */
21+ function bisection ( func : ( x : number ) => number , givenMin : number , givenMax : number , maxIter = 100 , annoyingConsoleLogs = false ) : number | [ number , number ] | "ERROR"
22+ {
23+ let posSlope = true ;
24+ let min = givenMin ;
25+ let max = givenMax ;
26+ let iter = 0 ;
27+
28+ console . log ( "---------------------------------------------------------------" ) ;
29+
30+ if ( givenMin > givenMax )
31+ {
32+ console . log ( "You seem to have mixed the min and max..." ) ;
33+ return "ERROR" ;
34+ }
35+ else if ( givenMin == givenMax )
36+ {
37+ console . log ( "The min and max given were the same..." ) ;
38+ return "ERROR" ;
39+ }
40+
41+ if ( func ( min ) > func ( min + max / 2 ) ) { posSlope = false ; }
42+
43+ while ( iter != maxIter )
44+ {
45+ iter ++ ;
46+ let guess = ( min + max ) / 2 ;
47+
48+ if ( ( func ( guess ) < 0 && posSlope ) || ( func ( guess ) > 0 && ! posSlope ) )
49+ {
50+ if ( guess == min )
51+ {
52+ console . log ( `Stopped at iteration #${ iter } ` ) ;
53+ console . log ( `Root not found.\nRange: (${ min } , ${ max } ).` ) ;
54+ return [ min , max ] ;
55+ }
56+ min = guess ;
57+ }
58+ else if ( ( func ( guess ) > 0 && posSlope ) || ( func ( guess ) < 0 && ! posSlope ) )
59+ {
60+ if ( guess == max )
61+ {
62+ console . log ( `Stopped at iteration #${ iter } ` ) ;
63+ console . log ( `Root not found.\nRange: (${ min } , ${ max } ).` ) ;
64+ return [ min , max ] ;
65+ }
66+ max = guess ;
67+ }
68+ else
69+ {
70+ console . log ( `Root: ${ guess } .\nIterations it took: ${ iter } .` ) ;
71+ return guess ;
72+ }
73+ if ( annoyingConsoleLogs )
74+ {
75+ console . log ( `Iteration #${ iter } :\n\tCurrent range: (${ min } , ${ max } )` ) ;
76+ }
77+ }
78+
79+ console . log ( `Root not found (maximum iterations reached).\nRange: (${ min } , ${ max } ).` ) ;
80+
81+ console . log ( "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." ) ;
82+
83+ return [ min , max ] ;
84+ }
85+
86+ /**
87+ * Just testing if everything generally works.
88+ * This is not an in-depth test (does not test all error scenarios).
89+ */
90+ function testBisectionFunction ( )
91+ {
92+ console . log ( "TESTING BISECTION FUNCTION!" ) ;
93+ /** Test linear function: (2x -19). */
94+ const linFunc = ( x : number ) => { return 2 * x - 19 ; }
95+
96+ /** Test polynomial function: (x^2 + x - 5). */
97+ const polyFunc = ( x : number ) => { return x ** 2 + x - 5 ; }
98+
99+ /** First test trigonometric function: sin(1/x). */
100+ const trigFuncOne = ( x : number ) => { return Math . sin ( 1 / x ) ; }
101+
102+ /** Second test trigonometric function: sin(x)/x. */
103+ const trigFuncTwo = ( x : number ) => { return Math . sin ( x ) / x ; }
104+
105+ const returnedVals : ( number | [ number , number ] | "ERROR" ) [ ] =
106+ [
107+ bisection ( linFunc , 100 , - 100 ) ,
108+ bisection ( linFunc , - 100 , 100 ) ,
109+ bisection ( polyFunc , 0 , 21 ) ,
110+ bisection ( trigFuncOne , 0.212 , 0.637 , 100000 ) ,
111+ bisection ( trigFuncTwo , 0.1 , 4.25 , 1000 /*, true*/ ) // those console logs really are annoying...
112+ ]
113+
114+ console . log ( "---------------------------------------------------------------" ) ;
115+ console . log ( `\nReturned values from bisection function:\n[` ) ;
116+
117+ // should I have just used a regular for loop: yes.
118+ let len = returnedVals . length ;
119+ let i = 0 ;
120+ for ( const returnedVal of returnedVals )
121+ {
122+ i ++ ;
123+ let toPrint ;
124+ switch ( typeof returnedVal )
125+ {
126+ case 'string' :
127+ toPrint = `\t"${ returnedVal } "` ;
128+ break ;
129+ case 'number' :
130+ toPrint = `\t${ returnedVal } ` ;
131+ break ;
132+ default :
133+ toPrint = `\t[${ returnedVal [ 0 ] } , ${ returnedVal [ 1 ] } ]` ;
134+ }
135+ if ( i != len ) { toPrint += ',' ; }
136+ console . log ( toPrint ) ;
137+ }
138+
139+ console . log ( `]` ) ;
140+ }
141+
142+ testBisectionFunction ( ) ;
0 commit comments