|
home—info—lects—labs—exams—hws
tutor/PIs—breeze (snow day)
Object120 + its docs—java.lang docs—java.util docs
Today's lab will (again) be done individually;
we well check off
Review: We have seen a loop that adds up all the numbers in [0,n) — that is, 0, 1, ..., n-1:
/** Return the sum of all the natural numbers numbers up to (but not including) n. * @param n The upper limit to sum to. * @return the sum of all the natural numbers numbers up to (but not including) n. */ static int sumUpTo( int n ) { int sumSoFar = 0.0; int i = 0; while (i < n) { // Each time through the loop, keep track of (in your head): // At this moment, i is , and sumSoFar is sumSoFar = sumSoFar + i; i = i + 1; } return sumSoFar; } |
We also saw that if we instead want to add up
(say) √0 + √1 + √2 + √3 + … + √(n-1),
we can have
/** Return the sum of *the square root of* all the natural numbers numbers up to (but not including) n. * @param n The upper limit to sum to. * @return the sum of the square root of all the natural numbers numbers up to (but not including) n. */ static double sumSqrtUpTo( int n ) { double sumSoFar = 0.0; int i = 0; while (i < n) { // Each time through the loop, keep track of (in your head): // At this moment, i is , and sumSoFar is sumSoFar = sumSoFar + Math.sqrt(i); i = i + 1; } return sumSoFar; } |
Looping over strings:
We can also use this same technique to loop over each character in a string.
First, let's imagine what we'd try if we didn't know about loops:
static void printEachChar( String wrd ) { System.out.println( "The char at index 0 is: '" + (wrd.charAt(0)) + "'" ); System.out.println( "The char at index 1 is: '" + (wrd.charAt(1)) + "'" ); System.out.println( "The char at index 2 is: '" + (wrd.charAt(2)) + "'" ); System.out.println( "The char at index 3 is: '" + (wrd.charAt(3)) + "'" ); System.out.println( "The char at index 4 is: '" + (wrd.charAt(4)) + "'" ); System.out.println( "The char at index 5 is: '" + (wrd.charAt(5)) + "'" ); // ⋮ } |
static void printEachChar( String wrd ) { if (0 < wrd.length()) { System.out.println( "The char at index 0 is: '" + (wrd.charAt(0)) + "'" ); } if (1 < wrd.length()) { System.out.println( "The char at index 1 is: '" + (wrd.charAt(1)) + "'" ); } if (2 < wrd.length()) { System.out.println( "The char at index 2 is: '" + (wrd.charAt(2)) + "'" ); } if (3 < wrd.length()) { System.out.println( "The char at index 3 is: '" + (wrd.charAt(3)) + "'" ); } // ⋮ } |
static void printEachChar( String wrd ) { int i = 0; if (i < wrd.length()) { System.out.println( "The char at index " + (i) + " is: '" + (wrd.charAt(i)) + "'" ); i = i + 1; } if (i < wrd.length()) { System.out.println( "The char at index " + (i) + " is: '" + (wrd.charAt(i)) + "'" ); i = i + 1; } if (i < wrd.length()) { System.out.println( "The char at index " + (i) + " is: '" + (wrd.charAt(i)) + "'" ); i = i + 1; } if (i < wrd.length()) { System.out.println( "The char at index " + (i) + " is: '" + (wrd.charAt(i)) + "'" ); i = i + 1; } // ⋮ } |
static void printEachChar( String wrd ) { int i = 0; // Or, "nextIndexToLookAt" while ( i < wrd.length() ) { System.out.println( "The char at index " + (i) + " is: '" + (wrd.charAt(i)) + "'" ); i = i + 1; } } |
Now we can take this last version, and actually do something useful with each character —
that is, with
/** Return the 'fingerprint' of a string -- * a number which is a summary of it's info (which is different from the fingerprint * of most other Strings, but not necessarily every other String. * This is also called a "hash value". * @param wrd The String to fingerprint. * @return `wrd`s fingerprint. */ static int fingerPrint( String wrd ) { int i = 0; // Or, "nextIndexToLookAt" int fingerPrintSoFar = 0; while ( i < wrd.length() ) { fingerPrintSoFar = fingerPrintSoFar + (int)(wrd.charAt(i)); i = i + 1; } return fingerPrintSoFar; } |
/** Test countOccurrences */ static void testCountOccurrences() { assertEqualInts( countOccurrences("abracadabra", 'a' ), ); assertEqualInts( countOccurrences("abracadabra", 'b' ), ); assertEqualInts( countOccurrences("abracadabra", 'd' ), ); assertEqualInts( countOccurrences("abracadabra", 'z' ), ); assertEqualInts( countOccurrences("AAA", 'A' ), ); assertEqualInts( countOccurrences("A", 'A' ), ); assertEqualInts( countOccurrences("A", 'b' ), ); assertEqualInts( countOccurrences("", 'b' ), ); } |
/** Return how many times given character occurs in a String. * @param s the string to search through * @param target the char to count. * @return how many occurrences of `target` occur in `s`. */ //Your stub here |
Finally, we'll write the actual body
of
Raise your hand, and we'll look at your test cases and check you off!
The following problems aren't required for today, but may be in the future -- or they might be for extra credit.
Variant:: If you want to implement 13-digit ISBN checksums instead of 10-digit, you are encouraged to. However, don't use the code from the wikipedia page; instead of having a two loops (one for odd indices, one for even) write your code using just one loop.
Ten-digit book numbers
— ISBN-10s
—
have the following “checksum” property:
the digits
x1x2x3…x9x10
have the property that
(1·x1 + 2·x2 + 3·x3 + … + 9·x9 + 10·x10) % 11 = 0.
This scheme means1that if somebody mis-types a digit, or transposes two digits,
a computer can recognize that an error has been made.
For example,
for the ten digits
( | 1·0 | + | 2·3 | + | 3·0 | + | 4·6 | + | 5·4 | + | 6·0 | + | 7·6 | + | 8·1 | + | 9·5 | + | 10·2 | ) | % 11 | |
= | ( | 0 | + | 6 | + | 0 | + | 24 | + | 20 | + | 0 | + | 42 | + | 8 | + | 45 | + | 20 | ) | % 11 |
= | 165 % 11 | |||||||||||||||||||||
= | 0 (since 11 goes into 165 fifteen times with remainder 0) |
Test case for you to try by hand,
to understand what our code will have to do:
Which of these is a valid ISBN-10?
By the way, mathemeticians have a concise way of writing this sum:
10 | ||||
( | Σ | i·xi | ) | mod 11 = 0 |
i=1 |
class ISBNChecker { boolean isValidISBN10( String isbn ) { return false; // stub. } } |
int charToInt( char digit ) { return Integer.parseInt( Character.toString(digit) ); } |
class ISBNCheckerTester { public static void main( String[] args ) { ISBNChecker looper = new ISBNChecker(); System.out.println( "\nTest some contrived ISBNs: " ); assertEqualBools( looper.isValidISBN10("0000000000"), true ); assertEqualBools( looper.isValidISBN10("1000000001"), true ); assertEqualBools( looper.isValidISBN10("1000000000"), false ); assertEqualBools( looper.isValidISBN10("0100000002"), true ); assertEqualBools( looper.isValidISBN10("0010000003"), true ); assertEqualBools( looper.isValidISBN10("0001000004"), true ); assertEqualBools( looper.isValidISBN10("0000000019"), true ); assertEqualBools( looper.isValidISBN10("0000000027"), true ); assertEqualBools( looper.isValidISBN10("2000000010"), true ); assertEqualBools( looper.isValidISBN10("4000000020"), true ); assertEqualBools( looper.isValidISBN10("5000000080"), true ); System.out.println( "\nTest some real and incorrect ISBNs: " ); assertEqualBools( looper.isValidISBN10("0306406152"), true ); assertEqualBools( looper.isValidISBN10("0306406162"), false ); assertEqualBools( looper.isValidISBN10("0306406154"), false ); assertEqualBools( looper.isValidISBN10("0553565699"), true ); assertEqualBools( looper.isValidISBN10("1553565699"), false ); } } |
Extra challenge:
Actually,
sometimes the check-digit works out to be 10.
Since that won't fit into a single digit,
in that case the letter
Fix your code above so that
ISBN-10s ending in the letter
System.out.println( "\nTest some X-digit ISBNs: " ); assertEqualBools( looper.isValidISBN10("000000000X"), false ); assertEqualBools( looper.isValidISBN10("050000000X"), true ); assertEqualBools( looper.isValidISBN10("000020000X"), true ); assertEqualBools( looper.isValidISBN10("300000002X"), true ); |
Here is code we've seen/written previously, for help in testing.
All you need for this assignment is
(You are welcome to make your own
/** If two booleans aren't equal, print an error message. * Intended for use as a test-helper. * @param act The actual boolean returned by a test call. * @param exp The expected boolean to be returned by a test call. */ static void assertEqualBooleans(boolean act, boolean exp) { if (act==exp) { System.out.println("(test passed)"); } else { System.out.println( "Actual: " + act + "\nExpect: " + exp ); } } /** If two ints aren't equal, print an error message. * Intended for use as a test-helper. * @param act The actual int returned by a test call. * @param exp The expected int to be returned by a test call. */ static void assertEqualInts(int act, int exp) { if (act==exp) { System.out.println("(test passed)"); } else { System.out.println( "Actual: " + act + "\nExpect: " + exp ); } } /** If two Strings aren't equal, print an error message. * Intended for use as a test-helper. * @param act The actual String returned by a test call. * @param exp The expected String to be returned by a test call. */ static void assertEqualStrings(String act, String exp) { if (act.equals(exp)) { System.out.println("(test passed)"); } else { System.out.println( "Actual: " + act + "\nExpect: " + exp ); } } /** If two doubles aren't (nearly) equal, print an error message. * Intended for use as a test-helper. * @param act The actual double returned by a test call. * @param exp The expected double to be returned by a test call. * @param tolerance The amount of tolerance allowed to still be considered equal * (an absolute amount.) * * BUG: the tolerance should probably be a relative to exp, at least when when exp!=0. */ static void assertEqualDoubles(double act, double exp, double tolerance) { if ( (act == exp) || (Math.abs(act-exp) < tolerance) || (Double.isNaN(act) && Double.isNaN(exp))) { System.out.println("(test passed)"); } else { System.out.println( "Actual: " + act + "\nExpect: " + exp ); } } /** If two doubles aren't (nearly) equal, print an error message. * Intended for use as a test-helper. * @param act The actual double returned by a test call. * @param exp The expected double to be returned by a test call. */ static void assertEqualDoubles(double act, double exp) { assertEqualDoubles(act,exp,TOLERANCE); } /** default The tolerance for assertEqualDoubles */ private static double TOLERANCE = 0.000001; |
1 In ITEC122, you'll learn why this is true. ↩
2 You might wonder why this formula works; from what we saw above, shouldn't x10 be the negative of that sum, so that ten times it will have the last digit cancel out the first nine? Yes! But in mod 11 (where we can subract a multiple of 11 without changing anything), ten times a number is equivalent to negative-one times that number. More on modular arithmetic in ITEC122. ↩
home—info—lects—labs—exams—hws
tutor/PIs—breeze (snow day)
Object120 + its docs—java.lang docs—java.util docs
©2012, Ian Barland, Radford University Last modified 2012.Oct.25 (Thu) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |