510 likes | 573 Views
More work with functions. Recall the “diary encoding problem”:. (We shifted letters of the alphabet one position to the left.) So IBM becomes HAL . And Mary becomes Lzqx. Here’s the complete program that writes the encoded information to another file.
E N D
Recall the “diary encoding problem”: • (We shifted letters of the alphabet one position to the left.) • So IBM becomes HAL. • And Mary becomes Lzqx.
Here’s the complete program that writes the encoded information to another file. Can we make a function out of the encoding part? That would make our code more readable and modular (in case we want to change the encoding). import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.Scanner; class Encode { public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); //perform encoding char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } out.close(); in.close(); } }
Java code segment for encoding: char enc; if (ch=='a') { //handle lowercase letters enc = 'z'; } else if (ch>'a' && ch<='z') { //handle lowercase letters enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { //handle uppercase letters enc = (char)(ch-1); } else { enc = ch; //unchanged }
Recall the steps to define your own function. • Decide on a name for your function. • Determine what arguments your function needs to do its job. • Determine the return type of your function. • Code your function.
Steps to define your own function. Step 1. Decide on a name. encode
Steps to define your own function. Step 2. Determine what arguments your functions needs to do its job. • What does encode need to do its job? • One character to check/translate. char before
After steps 1 and 2. encode ( char before ) { … } Step 3. What type of thing does our function return?
After steps 1 and 2. encode ( char before ) { … } Step 3. What type of thing does our function return? the encoded char
After steps 1, 2, and 3. static char encode ( char before ) { … } Now all we have to do is fill in the body of our function! The simplest encoder is one that doesn’t make any change. What should that encoder return?
After steps 1, 2, and 3. static char encode ( char before ) { return before; } Now all we have to do is fill in the body of our function. The simplest encoder is one that doesn’t make any change. How can we use this simple encoder function?
To use this simple encoder function, we first add it to our class (inside class definition but outside of main). … class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } ….
To use this simple encoder function, we first add it to our class. The next step is to replace the encoding code in main with a call to our encode function. … class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } ….
To use this simple encoder function, we first add it to our class. The next step is to replace the encoding code in main with a call to our encode function. What functions do we already call in main? … class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } ….
To use this simple encoder function, we first add it to our class. The next step is to replace the encoding code in main with a call to our encode function. We already call these functions in main! … class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } ….
So we replace all this with what? … class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged } outLine = outLine + enc; } out.println( outLine ); //output encoded line } ….
… class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); char enc = encode( ch ); outLine = outLine + encode( ch ); outLine = outLine + enc; } out.println( outLine ); //output encoded line } …. Both versions are fine.
… class Encode { static char encode ( char before ) { return before; } public static void main ( String args[] ) throws Exception { //open the input file Scanner in = new Scanner( new FileInputStream("diary.txt") ); //open the output file PrintWriter out = new PrintWriter( new FileOutputStream("out.txt") ); //read & write one line at a time while ( in.hasNextLine() ) { String s = in.nextLine(); String outLine = ""; System.out.println( "read: " + s ); for (int i=0; i<s.length(); i++) { char ch = s.charAt( i ); outLine += encode( s.charAt(i) ); outLine = outLine + encode( ch ); } out.println( outLine ); //output encoded line } …. This is OK as well.
… class Encode { static char encode ( char before ) { return before; } …. Now we need to complete the encode function based on our code from before: char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged }
… class Encode { static char encode ( char before ) { return before; } …. Note that ch below is called before w/in the scope of the encode function. Also for readability, since ch is before, let’s call encafter. char enc; if (ch=='a') { enc = 'z'; } else if (ch>'a' && ch<='z') { enc = (char)(ch-1); } else if (ch=='A') { //handle uppercase letters enc = 'Z'; } else if (ch>'A' && ch<='Z') { enc = (char)(ch-1); } else { enc = ch; //unchanged }
Our completed encode function … class Encode { //encode a given character for our secret code static char encode ( char before ) { char after; if (before=='a') { after = 'z'; } else if (before>'a' && before<='z') { after = (char)(before-1); } else if (before=='A') { //handle uppercase letters after = 'Z'; } else if (before>'A' && before<='Z') { after = (char)(before-1); } else { after = before; //unchanged } return after; } ….
Our completed encode function … class Encode { //encode a given character for our secret code static char encode ( char before ) { char after = before; //unchanged if (before=='a') { after = 'z'; } else if (before>'a' && before<='z') { after = (char)(before-1); } else if (before=='A') { //handle uppercase letters after = 'Z'; } else if (before>'A' && before<='Z') { after = (char)(before-1); } else { after = before; //unchanged } return after; } …. a slightly different way
Our completed encode function … class Encode { //encode a given character for our secret code static char encode ( char before ) { if (before=='a') { return ‘z‘; } else if (before>'a' && before<='z') { return (char)(before-1); } else if (before=='A') { //handle uppercase letters return 'Z'; } else if (before>'A' && before<='Z') { return (char)(before-1); } return before; //unchanged } …. a slightly different way
A function to approximate sine • From http://en.wikipedia.org/wiki/Trigonometric_function#Series_definitions
The sine function (blue) is closely approximated by its Taylor polynomial of degree 7 (pink) for a full cycle centered on the origin.
Let’s write a function to approximate sine • Use the following polynomial:
Recall the steps to define your own function. • Decide on a name for your function. • Determine what arguments your function needs to do its job. • Determine the return type of your function. • Code your function.
Steps 1 • Decide on a name for your function. almostSine
Steps 2 • Determine what arguments your function needs to do its job. almostSine ( double x )
Steps 3 • Determine the return type of your function. static double almostSine ( double x )
Steps 4 • Code your function. //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { }
Steps 4 • Code your function. //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = ?; double x7 = ?; double y = ?; return y; } Note: A loop over the number of terms is more general, but for simplicity we will use only 4 terms.
Steps 4 • Code your function. //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = ?; double fact5 = ?; double fact7 = ?; double y = ?; return y; }
Steps 4 • Code your function. //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = ?; return y; }
Steps 4 • Code your function. //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x – x3/fact3 + x5/fact5 – x7/fact7; return y; }
class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } How can we test our new function, almostSine?
class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } public static void main ( String args[] ) { for (double d=-2*Math.PI; d<=2*Math.PI; d+=Math.PI/2) { System.out.println( d + "\t" + Math.sin(d) ); } } } What does this print out? How can we modify it to print out the values of our new function as well?
class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } public static void main ( String args[] ) { for (double d=-2*Math.PI; d<=2*Math.PI; d+=Math.PI/2) { System.out.println( d + "\t" + Math.sin(d) + "\t" + almostSine(d) ); } } }
-12.566370614359172 4.898587196589413E-16 7525.149318866292 -10.995574287564276 1.0 2726.801987700507 -9.42477796076938 -3.6739403974420594E-16 821.0051310349569 -7.853981633974483 -1.0 189.61411535680668 -6.283185307179586 2.4492935982947064E-16 30.1591274102065 -4.71238898038469 1.0 3.602329768407337 -3.141592653589793 -1.2246467991473532E-16 0.0752206159036235 -1.5707963267948966 -1.0 -0.9998431013994987 0.0 0.0 0.0 1.5707963267948966 1.0 0.9998431013994987 3.141592653589793 1.2246467991473532E-16 -0.0752206159036235 4.71238898038469 -1.0 -3.602329768407337 6.283185307179586 -2.4492935982947064E-16 -30.1591274102065 7.853981633974483 1.0 -189.61411535680668 9.42477796076938 3.6739403974420594E-16 -821.0051310349569 10.995574287564276 -1.0 -2726.801987700507 12.566370614359172 -4.898587196589413E-16 -7525.149318866292 class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } public static void main ( String args[] ) { for (double d=-2*Math.PI; d<=2*Math.PI; d+=Math.PI/2) { System.out.println( d + "\t" + Math.sin(d) + "\t" + almostSine(d) ); } } } Can we format this better?
-12.57 0.00 7525.15 -11.00 1.00 2726.80 -9.42 -0.00 821.01 -7.85 -1.00 189.61 -6.28 0.00 30.16 -4.71 1.00 3.60 -3.14 -0.00 0.08 -1.57 -1.00 -1.00 0.00 0.00 0.00 1.57 1.00 1.00 3.14 0.00 -0.08 4.71 -1.00 -3.60 6.28 -0.00 -30.16 7.85 1.00 -189.61 9.42 0.00 -821.01 11.00 -1.00 -2726.80 12.57 -0.00 -7525.15 It’s nice and readable now. And the values are good from –Pi to +Pi. But something happens here… class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } public static void main ( String args[] ) { for (double d=-Math.PI; d<=2*Math.PI; d+=Math.PI/2) { System.out.printf( "%8.2f %8.2f %8.2f \n", d, Math.sin(d), almostSine(d) ); } } }
The sine function (blue) is closely approximated by its Taylor polynomial of degree 7 (pink) for a full cycle centered on the origin. Note what happens to our approximation outside of [-Pi,+Pi].
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. • Then we could use almostSine(f(x)) and get a reasonable value.
class MySine { //approx sine w/ a 7th degree polynomial static double almostSine ( double x ) { double x3 = x * x * x; double x5 = x3 * x * x; double x7 = x5 * x * x; double fact3 = 3 * 2; double fact5 = 5 * 4 * fact3; double fact7 = 7 * 6 * fact5; double y = x - x3/fact3 + x5/fact5 - x7/fact7; return y; } public static void main ( String args[] ) { for (double d=-Math.PI; d<=2*Math.PI; d+=Math.PI/2) { System.out.printf( "%8.2f %8.2f %8.2f \n", d, Math.sin(d), almostSine(f(d)) ); } } }
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. • So let’s start with the identity function: static double f ( double x ) { return x; }
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. static double f ( double x ) { //no change if in [-Pi..+Pi] if (-Math.PI<=x && x<=Math.PI) return x; return x; } How can we map each 2Pi interval to start at –Pi? (Did we use any arithmetic operator before that does this – random numbers and rolling dice?)
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. static double f ( double x ) { //no change if in [-Pi..+Pi] if (-Math.PI<=x && x<=Math.PI) return x; x %= 2*Math.PI; return x; } If this yields a number in [-Pi..+Pi], then this is fine.
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. static double f ( double x ) { //no change if in [-Pi..+Pi] if (-Math.PI<=x && x<=Math.PI) return x; x %= 2*Math.PI; if (-Math.PI<=x && x<=Math.PI) return x; return x; } If this yields a number in [-Pi..+Pi], then this is fine. Otherwise, we need to shift the result.
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. static double f ( double x ) { //no change if in [-Pi..+Pi] if (-Math.PI<=x && x<=Math.PI) return x; x %= 2*Math.PI; if (-Math.PI<=x && x<=Math.PI) return x; if (x>0) return x - 2*Math.PI; return x; } If this yields a number in [-Pi..+Pi], then this is fine. Otherwise, we need to shift the result.
So we need another function, f(x), which between –Pi and +Pi is x. • Outside of this range, we need to map each 2Pi interval to start at –Pi. static double f ( double x ) { //no change if in [-Pi..+Pi] if (-Math.PI<=x && x<=Math.PI) return x; x %= 2*Math.PI; if (-Math.PI<=x && x<=Math.PI) return x; if (x>0) return x - 2*Math.PI; return x + 2*Math.PI; } If this yields a number in [-Pi..+Pi], then this is fine. Otherwise, we need to shift the result.