Spring 2001 CS100M Exercise E12: A Whiff of Java Due: online *9*pm [was: 6pm], Friday, April 6 =============================================================================== goals =============================================================================== this exercise is to make sure you know how to: + run a Java program + save the textual output to a text file and to acquaint you with TokenReader for reading input =============================================================================== CodeWarrior Instructions (you're on your own if you use something else) =============================================================================== 0. you may work with a partner, but if you do so: + you might want to do it jointly at first + do it again with help from your partner to get familiar with all the steps + submit E12 separately 1. create a new project: + go to the File menu and select New... + this brings up a window, probably named New + click on Java Stationery + type in P6 for the Project Name + click on the Set... button or type in the Location where you want the project (folder and files) to be saved + click the OK button + this brings up a window, probably named New Project + either click on CUCS Java Application + or click on +Java2 + click on Java Application + and then click the OK button + this creates a project folder P6 that contains the project file P6.mcp and various other files and also brings up the project window P6.mcp note: + the project window has three tabs: Files, Link Order, Targets + we use only the Files tab 2. save the code for class $P6_1$ (provided below) in a text file named $P6_1.java$ inside the project folder. you can create a new text file in CodeWarrior by choosing New Text File from the File menu. 3. add file $P6_1.java$ to the project: + bring the CodeWarrior window containing $P6_1.java$ to the front + go to the Project menu and select Add Window. (it doesn't matter where P6_1.java ends up in the P6.mcp window.) 3'. set $P6_1$ as the target class: + go to the Edit menu + select Java Application Settings... + click on Java Target under Target in the left panel + type in $P6_1$ exactly --not $p6_1$ or $P6_1.java$-- for the Main Class + click Save + do NOT confuse Target Settings (under Target) with Java Target: + if you see a field for "Target Name" instead of "Main Class", you are not using the correct panel + if you run the project and the program asks for an integer, a floating number, and various other things, you're seeing the code for class CUCSApplication and therefore you did not set the target class correctly. 4. if you used CUCS Java Application stationery, then TokenReader.java (code provided below) should already be part of the project; otherwise, follow steps 2 and 3 with TokenReader.java in place of P6_1.java 5. run the code: + choose Run from the Project menu + or hit the F5 key on a PC + or hit Command-R on a Mac 6. this brings up a java console window; inside the console window, type the following input all on the same line: 17 0 -2 -4 -6 -9 -12 15 11 10 9 2 1 5 9 13 17 -1 28 46 7. save the output to a text file: + on mac, select the text, copy it, paste it into a text file + on a pc + mark the text: + press on the upper left corner of the java console window + go to the Edit menu + select Mark + click and drag to highlight a rectangle containing all the output + copy the text: + hit the ENTER key + or + press on the upper left corner of the java console window + go to the Edit menu + select Copy + paste the text into a text file 8. do not edit the text file with the output except to add at the top the required homework and identity information and submit the text file online by 6pm, Friday, April 6. =============================================================================== notes =============================================================================== + the consultants in carpenter are very familiar with codewarrior and java: ask them for help if you have problems -- it can be hard to explain what to do online (e.g. see the instructions above!) + don't try to understand the code in TokenReader at this point; we haven't covered enough material for that + $TokenReader in = new TokenReader(System.in);$ creates a variable $in$ that holds a reference to a $TokenReader$ object that can read input + $in.readInt()$ asks the object referenced by $in$ to read an integer and return the value + unlike in matlab, multiple numbers can be entered all at once (without enclosing them in braces) + we ask you to type all the input on one line, but try break the input up into more lines, e.g. 17 0 -2 -4 -6 -9 -12 15 11 10 9 2 1 5 9 13 17 -1 28 46 also try typing in only one number per line; you should find that the program ends ($"Press Enter to Continue"$ shows up) before you can type in 28 and 46. + observe that some lines were too long to fit within 80 columns and were broken up over multiple lines; long strings were broken up into smaller strings and concatenated back together using $+$ + in case it is helpful, a roughly equivalent matlab script file is provided, but, you should first try to understand the java code without looking at it. =============================================================================== java file $P6_1.java$ =============================================================================== // print rightmost, longest, arithmetic subsequence in a // pre-sorted $-1$-terminated input sequence public class P6_1 { public static void main(String[] args) { // initialize $TokenReader$ object $in$ to read from standard input TokenReader in = new TokenReader(System.in); // print rightmost, longest, arithmetic subsequence in a // pre-sorted $-1$-terminated input sequence int stopping = -1; // stopping value // prompt user for input System.out.println( "please enter a sequence of integers terminated by " + stopping); System.out.println("separate numbers with white space"); System.out.println("use one or more lines"); int num = in.readInt(); // current input value int prev = num; // previous input value // rightmost, longest arithmetic subsequence so far -- // up to but excluding $num$ int longestLo = num; // start int longestGap = 0; // gap int longestLen = 0; // length // "current" subsequence: longest arithmetic subsequence // ending on $prev$ int curLo = num; // start int curGap = 0; // gap int curLen = 0; // length // process $stopping$-terminated input sequence // inv: maintain variable definitions above while (num != stopping) { // update current subsequence if (curGap == num - prev) { curLen = curLen + 1; // update rightmost, longest arithmetic subsequence if (curLen >= longestLen) { longestLo = curLo; longestLen = curLen; longestGap = curGap; } } else { curLo = prev; curGap = num - prev; curLen = 2; } // read next input value prev = num; num = in.readInt(); // current input value } // display rightmost, longest arithmetic subsequence System.out.print("rightmost, longest arithmetic" + " subsequence: ["); int i = 0; while (i < longestLen) { System.out.print(" " + (i * longestGap+longestLo) ); i = i + 1; } System.out.println(" ]"); } } =============================================================================== java file $TokenReader.java$ =============================================================================== // Simple text input class for Cornell CS // H. Perkins 7/97, 8/97, 1/98, 6/98 // File input constructor added by M Godfrey, 1/98 // Inspired by an idea in J. Bishop "Java Gently", A-W, 1997. import java.io.*; import java.util.*; class TokenReader { // Simple text input from keyboard and files. Input is parsed into tokens separated // by whitespace. Tokens are returned as either int, double, or String values depending // on the input method. If an int or double is requested and the next token is not a // properly formatted integer or floating-point number, an error message is written to // the console (actually System.err) and the method will repeatedly read tokens until // one with the proper format is read. // // Here is an example of the use of this class by a client: // // TokenReader in = new TokenReader(System.in); // // int k = in.readInt(); // double d = in.readDouble(); // String s = in.readString(); // String t = in.readLine(); // // The identifiers s, d, k, and in are arbitrary. Also, note that function readLine() // discards any unused input on the current line and returns the next input line // as a single string. // // TokenReader input does not throw any IOExceptions. To detect the end of the stream, // function eof is provided. The expression // // in.eof() // // evaluates to true if the end of stream in has been encountered, false otherwise. // Example: // // k = in.readInt(); // while (!in.eof()) { // // k = in.readInt(); // } // // If an attempt is made to read past the end of the stream, an error message is // written to System.err and the input function evaluates to an unspecified result. // // Finally, the operation // // in.waitUntilEnter(); // // prints a message on the screen and then reads and discards a line of input. It can // be used to pause execution to, for example, ensure that the console window remains // visible until the user chooses to terminate the program (a problem with the Windows // console window). // // Class TokenReader can be used to read any InputStream, not just System.in. Use the // desired stream as the parameter in the "new TokenReader(...)" allocation. // // Technical note: TokenReader is not derived from InputStream or any other stream class // because it does not provide the normal interface of a java.io input stream. // Local state private DataInputStream theStream; // the stream being read private boolean eofReached = false; // = "end of theStream has been encountered" private String S; // current input line private StringTokenizer T; // parser for current input line // T==null means no more available tokens // on this line (including when eofReached). // Constructors: a TokenReader object for input stream s or ds. (The second constructor // is provided to reduce overhead if the desired stream is already a DataInputStream.) public TokenReader(InputStream s) { theStream = new DataInputStream(s); } public TokenReader(DataInputStream ds) { theStream = ds; } // Constructor: a TokenReader object connected to file fileName. public TokenReader(String fileName) { try { FileInputStream fis = new FileInputStream (fileName); theStream = new DataInputStream(fis); } catch (FileNotFoundException e) { System.err.println ("Sorry, couldn't find file " + fileName + " for some reason."); } } // Yield next integer from stream. // If the next token is not an integer, print an error message on System.err and // continue reading input until an integer is read. // If the end of the file is encountered before finding an integer, the smallest // integer Integer.MIN_VALUE is returned. public int readInt () { String item = ""; // next token as a string if (T == null) refresh(); while (true) { if (eofReached) return Integer.MIN_VALUE; try { item = T.nextToken(); return Integer.parseInt(item.trim()); } catch (NoSuchElementException e) { refresh(); } catch (NumberFormatException e) { System.err.println("Integer expected but input was \"" + item + "\". Please try again."); } } } // Yield next double from stream. // If the next token is not a double, print an error message on System.err and // continue reading input until a floating-point number is read. // If the end of the file is encountered before finding an double, a NaN is returned. public double readDouble () { String item = ""; // next token as a string if (T == null) refresh(); while (true) { if (eofReached) return Double.NaN; try { item = T.nextToken(); return Double.valueOf(item.trim()).doubleValue(); } catch (NoSuchElementException e) { refresh(); } catch (NumberFormatException e) { System.err.println("Double expected but input was \"" + item + "\". Please try again."); } } } // Yield next string from stream or an appropriate error message if // attempting to read past eof. public String readString () { if (T == null) refresh(); while (true) { if (eofReached) return "readString called after reaching end of TokenReader stream."; try { return T.nextToken(); } catch (NoSuchElementException e) { refresh(); } } } // Yield the next input line from stream as a single string or an // appropriate error message if attempting to read past eof. // Unused input remaining in the current line is discarded. public String readLine () { refresh(); if (eofReached) return "readLine called after reaching end of TokenReader stream."; // return new line and mark current line as fully read String line = S; T = null; return line; } // Yield "end of stream has been reached" (i.e. no more data) public boolean eof() { return eofReached; } // Write prompt to output, then wait until user enters an input line public void waitUntilEnter() { System.out.println(); System.out.println("Press Enter to continue."); try { theStream.read(); } catch (java.io.IOException e) {} } // Read next input line into S and initialize tokenizer T to parse it. // Print appropriate error messages to System.err if attempting to read // past end of stream or some other I/O error occurs. private void refresh () { // print error message and return if eof already encountered. if (eofReached) { System.err.println("Attempt to read past end of TokenReader stream."); return; } // read next line into S and T try { S = theStream.readLine(); } catch (EOFException e) { eofReached = true; T = null; return; } catch (IOException e) { System.err.println("Unexpected error reading TokenReader input.\nIOException: " + e); return; } if (S == null) { eofReached = true; T = null; } else T = new StringTokenizer(S); } } // end of class TokenReader =============================================================================== matlab script file $P6_1.m$ =============================================================================== stopping = -1; % stopping value prompt = sprintf('next number (%d to stop)? ', stopping); % input prompt num = input(prompt); % current input value prev = num; % previous input value % rightmost, longest arithmetic subsequence so far -- up to but excluding $num$ longest.lo = num; % start longest.gap = 0; % gap longest.len = 0; % length % "current" subsequence: longest arithmetic subsequence ending on $prev$ cur = longest; % process $stopping$-terminated input sequence % inv: maintain variable definitions above while num ~= stopping % update current subsequence if cur.gap == num - prev cur.len = cur.len + 1; % update rightmost, longest arithmetic subsequence so far if cur.len >= longest.len longest = cur; end else cur.lo = prev; cur.gap = num - prev; cur.len = 2; end % read next input value prev = num; num = input(prompt); end % display rightmost, longest arithmetic subsequence fprintf('rightmost, longest arithmetic subsequence: ['); fprintf(' %d', (0:longest.len-1)*longest.gap+longest.lo); fprintf(' ]\n');