Introduction to Computer Science

Start Lecture #3

Remark: I mistakenly typed in the wrong problem 2.5 (I typed in 2.2). You may do either. By tomorrow the notes will be corrected.

2.8.1: Numeric Operators

Java, like essentially all languages, defines +, -, *, and / to be addition, subtraction, multiplication, and division.

    (-1) % 5 == -1
    (-1) modulo 5 == 4
  
Java defines % to be the remainder operator. Some people (and some books and some web pages) will tell you that Java defines % to be the mathematical modulo operator. Don't believe them. Remainder and modulo do agree when you have positive arguments, but not in general.

2.8.2: Numeric Literals

Literals are constants that appear directly in a program. We have already seen examples of both numeric and string literals.

For integers, if the literal begins with 0 followed by a digit, the value is interpreted as octal (base 8). If it begins with 0x, it is interpreted as hexadecimal (base 16). Otherwise, it is interpreted as decimal (base 10).

What is the use of base 8 and base 16 for us humans with 10 fingers (i.e, digits)?
Ans: Getting at individual bits.

The literal is considered an int unless it ends with an l or an L

Real numbers are always decimal. If the literal ends with an f or an F, it is considered a float. By default a real literal is a double, but this can be emphasized by ending it with a d or a D.

Scientific Notation

Literals such as 6.02×1023 (Avogadro's number) can also be expressed in Java (and most other programming languages). Although the exact rules are detailed, the basic idea is easy: First write the part before the × then write an e or an E (for exponent) then write the exponent. So Avogadro number would be 6.02E23. Negative exponents get a minus sign (9.8E-3).

The details concern the optional + in the exponent, the optional trailing d or D, the trailing f or F for float, and the ability to omit the decimal point if it is at the right.

2.8.3: Evaluating Java Expressions

This is quite a serious subject if one considers arbitrary Java expressions. In general, to find the details, one should search the web using site:sun.com. This leads to the Java Language Specification http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html. The chapter on expressions http://java.sun.com/docs/books/jls/third_edition/html/expressions.html is 103 pages according to print preview on my browser!

For now we restrict ourselves to arithmetic expressions involving just +, -, *, /, %, (, and ). In particular, we do not now consider method evaluation. In this case the rules are not hard and are very similar to the rules you learned in algebra.

  1. Evaluate (innermost) parenthesized parts first and then erase the parentheses (e.g. 3*(5+2) is 21).
  2. Within a parenthesized part evaluate all *, /, % in one left-to-right pass.
    So (7 * 4 % 5) + 12 = 3 + 12 == 15
  3. Within a parenthesized part, after doing *, /, and %, do all + and - in one left-to-right pass.
    So (7 + 3 * 2) / (1 + 2 * 2) == (7 + 6) / (1 + 4) = 13 / 5 = 2

The last step illustrated integer division, which in Java rounds towards zero.
So (5 - 12) / 4 = (-7) / 4 == -1.

Note that these operators are binary. We have unitary operators as well, e.g., unitary -, which are evaluated first.
So 5 + - 3 == 2 and - 5 + - 3 == -8

Unary + is defined as well, but doesn't do much. Unary (prefix) operators naturally are applied right to left
So 5 - - - 3 == 2 and 5 + + + + 3 == 8

2.9: Problem: Displaying the Current Time

2.9 (Alternate): Computing How long Ago

// Silly version of How Long Ago
import java.util.Scanner;
public class HowLongAgo {
    public static void main (String[] args) {
	final int daysInMonth = 30; // ridiculous
	final int daysInYear = 360; // equally ridiculous
	Scanner getInput = new Scanner(System.in);
	System.out.println("Enter today's day, month, and year");
	int day = getInput.nextInt();
	int month = getInput.nextInt();
	int year = getInput.nextInt();
	System.out.println("Enter old day, month, and year");
	int oldDay = getInput.nextInt();
	int oldMonth = getInput.nextInt();
	int oldYear = getInput.nextInt();
	// Compute total number of days ago
	int deltaDays = (day-oldDay) + (month-oldMonth)*daysInMonth
	    + (year-oldYear)*daysInYear;
	// Convert to days / months / years
	int yearsAgo = deltaDays / daysInYear;
	int monthsAgo = (deltaDays % daysInYear) / daysInMonth;
	int daysAgo = (deltaDays % daysInYear) % daysInMonth;
	System.out.println ("The old date was " + yearsAgo +
			    " years " + monthsAgo + " months and "
			    + daysAgo + " days ago.");
    }
}

It is no fun to do one from the book so instead we do a silly version of a program to tell how long it is from one date to another. For example from 1 July 1980 to 5 September 1985 is 5 years, 2 months and 4 days.

However, we will do a silly version since we don't yet know about arrays and if-then-else.

  1. We pretend that all months have 30 days and hence that a year has 30×12=360 days.
  2. We require that the user give the later date first. Actually we call it today's date, but it can be any date providing it is later than the second date.

The program (on the right) performs this task in three steps.

  1. Prompt for and read in the input.
  2. Compute the total number of days between the two dates.
  3. Convert the days into years/months/days. This uses the remainder operator % and should be studied.

Note that monthsAgo is not the total number of months ago since we have already removed the years.

I computed the three values in the order days, months, years, which is from most significant to least significant. You can instead compute the values in the reverse order (least to most significant). To see an example, read the book's solution.

Splitting a combined value into parts is actually quite useful. Consider splitting a 3-digit number into its three digits. For example given six hundred fifteen, we want 6, 1, and 5. This is the same problem as in our program but daysInYear is 100 and daysInMonth is 10.

How would you convert a number into millions, thousands, and the rest?
Ans: Set daysInYear = 1,000,000 and daysInMonth = 1,000.

How would you convert dollars into hundreds, twenties, and singles?
Ans: Set daysInYear to 100 and daysInMonth to 20.

How can an operating system convert a virtual address into segment number, page number, and offset
Ans: Set daysInYear to the number of bytes in a segment and ... oops wrong course (and real OSes do it differently).

Homework: 2.7 Write a program that prompts the user to enter the number of minutes and then calculates the (approximate) number of years and days it represents. Assume all years have 365 days.

2.10: Shorthand Operators

Statements like x = x + y; are quite common and several languages, including Java have a shorthand form x += y;.

Similarly Java et al. has -=, *=, /=, and %=. Note that there is no space between the arithmetic operator and the equal sign.

An especially common case is x = x + 1; and Java and friends have an especially short form x++. Similarly, we have x-- (but NOT ** or // or %%).

In fact x++ can be part of an expression rather than as a statement by itself. In this case, a question arises. Is the value used in the expression the old (un-incremented) value of x, or the new (incremented) value? Both are useful and both are provided.

    x  = 5;
    y1 = x++ + 10;
    y2 = ++x + 10;
    y3 = x-- + 10;
    y4 = --x + 10;
  
Consider the code sequence on the right where all 5 variables are declared to be ints.
  1. The first line simply sets x to 5.
  2. The second line clearly increments x to 6, but is y1 set to 5+10 or 6+10? Ans: x++ is a post-increment, that is the increment is done after the value of x is supplied to the remaining expression. Thus y1 becomes 5+10=15. As a mnemonic hint the ++ comes after and the increment comes after the value of x is returned.
  3. The third line clearly increments x to 7, but this time we have a pre-increment (the ++ comes before and the increment is done before the value of x is returned.
    Thus y2 becomes 7+10=17.
  4. The rules for -- are the same as for ++ so the fourth line clearly decrements x to 6. It is a post-decrement, occurring after the value of x is returned. Thus y3 becomes 7+10=17.
  5. Clearly the last line decrements x back to 5. It is a pre-decrement occurring before the value of x is returned. Thus y4 becomes 5+10=15;
Since there were two increments and two decrements, we expect x to end with the same value as it had in the beginning.

On the board show how to calculate the index for queues (rear++ and front++) and for stacks (top++ and --top). What about moving all four ++ and -- operators to the other side?

2.11: Numeric Type Conversions

What happens if we try to add a short to an int? How about multiplying a byte by a double?

Even simpler perhaps, how about assigning an integer value to a real variable, or vice versa?

The strict answer is that you can't do any of these things directly. Instead one of the values must be converted to another type.

Sometimes this happens automatically (but it does happen). Other times it must be explicitly requested and some of these requests fail.

Coercion vs. Casting

When the programming language automatically converts a value of one type (e.g. integer) to another type (e.g., double), we call the conversion a coercion. When the programmer explicitly requests the conversion, we call it type casting.

Widening vs. Narrowing

Any short value is also a legal int. Similarly any float value is a legal double.

Conversions of this kind are called widenings since the new type in a sense is wider than the old. Similarly, the reverse conversions are called narrowing.

public class Test {
  public static void main (String[] args) {
    int a = 1234567891;   // one billion plus
    short b;
    double x;
    float y;
    x = a;
    y = a;
    b = a;  // error coercions cannot narrow 
    b = (short)a;    // narrowing cast
    System.out.println(a + " " + b + " "
		       + x + " " + y);
  }
}
javac Test.java; java Test
1234567891 723 1.234567891E9 1.23456794E9
  

Java will perform widening coercions but not narrowing coercions. To perform a narrowing conversion, the programmer must use an explicit cast. This is done by writing the target type in parenthesis.

The code on the right illustrates these points. Two problems have arisen.

  1. The narrowing from a to b was disasterous: 1234567891 has become 723. Not all 32-bit numbers fit in 16 bits. No wonder Java won't do the coercion and requires you to emphasize that you really mean it!
  2. The coercion from a to y resulted in some loss of precision. A 32-bit float uses some bits for the exponent so does not have as many available for the mantissa as does a 32-bit int, which has no exponent. A 64-bit double has more than enough mantissa bits to exactly represent any int, but not enough for very large longs.

2.12: Problem: Computing Load Payments

The load payment problem requires you to accept some complicated formula for monthlyPayment. That is not my style. Instead, we will do a simpler problem where we can understand the formula used.

Problem: Computing Compound Interest

Say you have a bank account with $1000 that pays 3% interest per year and want to know what you will have after a year.

import java.util.Scanner;
  public class CompoundInterest {
  public static void main (String[] args) {
    Scanner getInput = new Scanner(System.in);
    double origBal = getInput.nextDouble();
    double interestRate = getInput.nextDouble();
    int n = getInput.nextInt();   // numberCoumpoundings
    double finalBal = origBal*Math.pow(1+interestRate/n,n);
    System.out.println(finalBal);
  }
}
javac CompoundInterest.java; java CompoundInterest
1000. .03 1
1030.0
java CompoundInterest
1000. .03 2
1030.2249999999997
java CompoundInterest
1000. .03 12
1030.4159569135068
java CompoundInterest
1000. .03 100000
1030.4545293116412
java CompoundInterest
1000. .03 1000000
1030.4545335307425
  

The program on the right is fairly straigtforward, given what we have done already. First we read the input data: the original balance, the (annual) interest rate, and the number of compoundings.

Then we compute the final balance after one year. We could do k years by changing the exponent from n to k*n.

Finally, we print the result

The only interesting line is the computation of finalBal. Let's read it carefully in class to check that it is the same as the formula above.

We show five runs, the first for so called simple interest (only compounded once). We did this above and sure enough we again get $1030 for 3% interest on $1000.

The second is semi-annual compounding. Note that we do not need to recompile (javac).

The third is monthly compounding.

The fourth and fifth suggest that we are approaching a limit.

2.13: Character Data Type and Operations

  char c = 'x';
  string s = "x";
  s = c;   // compile error

The char (character) datatype is used to hold a single character. A literal char is written as a character surrounded by single quotes.

The variables c and s on the right are most definitely not the same.

2.13.1: Unicode and ASCII code

Java's char datatype uses 16-bits to represent a character, thereby allowing 216=65,536 different characters. This size was inspired by the original Unicode, which was also 16 bits. The goal of Unicode was that it would supply all the characters in all the world's languages.

However, 65,536 characters proved to be way too few; Unicode has since been revised to support many more characters (over a million), but we won't discuss how it was shoehorned into 16-bit Java characters. It turns out that the character 'A' has the 16-bit value 0000000000100001 (41 in hex, 65 in decimal).

There are two ways to write this character. Naturally 'A' is one, but the other looks wierd, namely '\u0041'. This representation consists of a backslash, a lower case u (presumably for unicode), and exactly 4 hexadecimal digits. I don't like this terminology—to me digit implies base 10—but it is standard.

public class As {
  public static void main(String[] Args) {
    String str = "A\u0041\u0041A \u0041";
    System.out.println(str);
  }
}
javac As.java; java As
AAAA A
  

So 'A' is the 4*16+1=65th character in the Unicode set.

The two character representations can be mixed freely, as we see on the right.

In the not so distant past, computers (at least US computers) used the 7-bit ASCII code (rather nationalistically, ASCII abbreviates American Standard Code for Information Interchange). The 65th ASCII character is also 'A'. All the normal letters, digits, etc are in both ASCII and are in the same position (65 for A). It might be right that the 127 ASCII codes make up the first 127 unicode characters and are at the same position, but I am not sure.

Although it will not be emphasized in this course, it is indeed wonderful that alphabets from around the world can be represented.

2.13.2: Escape Sequences for Sepcial Characters

Esc SeqBecomes


\"Double quote
\\Backslash
\'Single quote
\tTab
\nNewline


\bBackspace
\fFormfeed
\r(carriage) Return

We have a problem. The character " is used to end a string. What do we do if we want a " to be part of a string?

We use an escape sequence beginning with \. In particular we use \" to include a " inside a string.

But then how do we get \ itself?
Ans: We use a \\ (of course).

On the right is a list of Java escape sequences. The ones above the line are more commonly used than the ones below.

2.13.3: Casting between char and Numeric Types

public class Test {
  public static void main (String[] args) {
    int i;
    short s;
    byte b;
    char c = 'A';
    i = c;
    s = c;
    b = c;
    System.out.println(c + " " + i + " " + s + " " + b);
  }
}

I believe a better heading would be converting between char and numeric types since not all of the conversions used are (explicit) casts; some are (implicit) coercions.

The code on the right has two errors. Clearly a (16-bit) char may not fit into an (8-bit) byte. The (subtle) trouble with the short is that it is signed.

So coercions will not work. You may write casts such as b=(byte)c; this will compile but will produce wrong answers if the actual value in the char c does not fit in the byte b.

Similarly, integer values may be cast into chars (but not coerced).

2.14: Problem: Counting Monetary Units

We already did a simpler version of this.

Let's do the design of a more complicated version: Read in a double containing an amount of dollars and cents, e.g., 123456.23 and prints the number of twenties, tens, fives, singles, quarters, dimes, nickels, pennies.

There is a subtle danger here that we will ignore (the book doesn't even mention it). A number like 1234.1 cannot be represented exactly as a double since 0.1 cannot be written in base 2 (using a finite number of bits) just as 1/3 cannot be written as a decimal.

Ignoring the problem, the steps to solve the problem are

  1. Convert the dollars and cents to an integer number of pennies.
  2. Find the number of twenties and subtract the corresponding number of pennies.
  3. Find the number of tens and subtract the corresponding number of pennies.
  4. ...
  5. Find the number of nickels and subtract the corresponding number of pennies.
  6. What is left is the number of pennies.