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.
Java, like essentially all languages, defines +, -, *, and / to be addition, subtraction, multiplication, and division.
(-1) % 5 == -1 (-1) modulo 5 == 4Java 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.
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.
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.
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.
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
// 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.
The program (on the right) performs this task in three steps.
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.
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.
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?
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.
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.
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.
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.
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.
finalBalance = origBalance + interest = origBalance + origBalance * interestRate = origBalance * (1 + interestRate)
finalBalance = origBalance * (1 + interestRate/12)12
finalBalance = origBalance * (1 + interestRate/365)365
finalBalance = origBalance * (1 + interestRate/n)n
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.
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.
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.
Esc Seq | Becomes |
---|---|
\" | Double quote |
\\ | Backslash |
\' | Single quote |
\t | Tab |
\n | Newline |
\b | Backspace |
\f | Formfeed |
\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.
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).
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