Reminder: when we are not using graphics, we start from this gray/green code:
public class SampleCode { public static java.util.Scanner scanner = new java.util.Scanner(System.in); public static void main(String[] args) { // place your code here! } }
1. Doubles
(or "Floating Point Numbers")
(or "Numbers with Decimals")
So far, all our variables have been integers. Java supports other types of variables, too. For example, you can use floating point numbers in Java. These are numbers with decimals, such as 3.14159. These values are not integers, and so cannot be stored in integer variables. For example, this code will not work:
int x = 3.14; // WILL NOT WORK!
When we declare the variable x to be of type "int", we are requiring that it only hold integer values. So it cannot hold the value 3.14.So we need a new type of variable that can hold floating point numbers. For historical reasons, this is called a "double". Despite the peculiar name, this is a handy variable type. It works like this:
double d = 3.14;Doubles differ from ints in several ways:
1) Doubles can hold decimal values (like 3.14) and ints cannot.
In particular, doubles can hold fractions between 0 and 1 (like 0.5), and ints cannot. For example:
double d = 1;
int x = 1;
x /= 2;
d /= 2;
System.out.println(x); // prints 0
System.out.println(d); // prints 0.5
2) Doubles have a much larger range than ints.
The largest positive int is about 2 billion, but the largest positive double is about 10308 (which is way larger!). For example:
System.out.println(Integer.MAX_VALUE); // prints 2147483647
System.out.println(Double.MAX_VALUE); // prints 1.7976931348623157E308
Also, the smallest positive int is 1, but the smallest positive double is about 10-324, also written as 1/10324 (which is very close to zero). For example:
System.out.println(Double.MIN_VALUE); // prints 4.9E-3243) Doubles are approximate and ints are exact.
Unlike ints, Java stores doubles as approximate values rather than exact values. For example:
double d = (29 / 7.0) * 7.0;
Here, the value "d" seems like it should equal 29 (seeing as we divide 29 by 7 and then multiply the result by 7 again). But this is not quite what happens, as we see when we print out the value:
double d = (29 / 7.0) * 7.0;
System.out.println(d); // prints 29.000000000000004, not 29
So we see that Java introduced a very small round-off error of 0.000000000000004. This is very small indeed! But it is non-zero, and leads to a serious problem when comparing doubles, as we will discuss in a moment (once we learn about boolean variables).4) Doubles have some special constant values that ints do not have.
Unlike ints which have no special constant values, doubles have three special constant values. Two of these represent positive and negative infinity. These are Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY. The third value is Double.NaN, which stands for "Not a Number", which is the result of various illegal operations. Perhaps strangely, these three values are all valid values for double variables to hold. For example:
double d1 = Double.POSITIVE_INFINITY;
double d2 = Double.NEGATIVE_INFINITY;
double d3 = Double.NaN;
System.out.println(d1+d1); // prints out Infinity (which is positive infinity)
System.out.println(d2+d2); // prints out -Infinity (which is negative infinity)
System.out.println(d1+d2); // prints out NaN (not a number)
System.out.println(d1+d3); // prints out NaN (not a number)
Do you see why each of the last two lines prints out NaN?
5) Doubles do not throw exceptions the same way ints do.
As you know, in integer math, Java throws an exception when you divide by zero. For example:
System.out.println(5/0);
This code will throw a DivisionByZeroException, as expected. However, this is not what happens with double math:
System.out.println(5.0/0.0);
Instead of complaining about dividing by zero, this actually succeeds, and prints out Infinity! Why? Well, if you divide 5.0 by a very small number, say, 0.00000001, you will get a very large number, like 500000000. The smaller the denominator, the larger the result. By this logic, if we divide by zero, we should get infinity, which is just what Java does! And by the same logic:
System.out.println(-5.0/0.0);
prints out -Infinity.There are other cases where Java gives surprising results:
System.out.println(0.0/0.0);
In this case, Java has two different rules to follow: 0.0 divided by any number equals 0, but any (non-negative) number divided by 0.0 equals infinity. Not knowing whether to evaluate to 0 or infinity, Java does neither, instead evaluating to NaN ("not a number"). Fascinating!
More practice:
- Problem #1: Java prints double values and int values differently -- even when a double value is an integer. Run the following code and explain its output:
double d = 1;
int x = 1;
System.out.println(x);
System.out.println(d);
- Problem #2: Note that Java performs integer math when both values are integers. However, if either value is a double, Java converts the other value to a double if necessary and performs double math. Using this fact, predict what the following code will print out. Write down your answers. Then (and only then) run the program and compare its output to your answers.
- System.out.println(1 + 2);
System.out.println(1.0 + 2);
System.out.println(1 + 2.0);
System.out.println(1.0 + 2.0);
- System.out.println(5 / 2);
System.out.println(5.0 / 2);
System.out.println(5 / 2.0);
System.out.println(5.0 / 2.0);
System.out.println(1 + 2 * 3 / 4);
System.out.println(1 + 2 * 3 / 4.0);
System.out.println(1.0 + 2 * 3 / 4);
System.out.println(1 + 2.0 * 3 / 4);
System.out.println(6 + 5 / 4 * 3); System.out.println(6.0 + 5 / 4 * 3); System.out.println(6 + 5.0 / 4 * 3); System.out.println(6 + 5 / 4.0 * 3); System.out.println(6 + 5 / 4 * 3.0); double d1 = 3; double d2 = 5 / d1; double d3 = 5 / 3; System.out.println(d1); System.out.println(d2); System.out.println(d3); double d1 = 5.0/0.0; double d2 = 0.0 - 2*d1; double d3 = d2 / d1; System.out.println(d1); System.out.println(d2); System.out.println(d3);
2. Booleans
So far, all our variables have been numbers -- ints or doubles. Java supports non-numeric variables, too. The simplest non-numeric type is "boolean". A boolean variable can hold one of two values: true or false. For example:
boolean b1 = true;
boolean b2 = false;
System.out.println(b1); // prints true
System.out.println(b2); // prints falseEquality Operators
Just as we have operators that produce numeric results, like +, -, *, /, and %, we also have operators that produce boolean results (true or false). For example, we can use an equality operator to test if ints are equal using "==" (two equal signs in a row):
boolean b1 = (1 == 1); // does 1 equal 1? Yes!
boolean b2 = (1 == 2); // does 1 equal 2? No!
System.out.println(b1); // prints true
System.out.println(b2); // prints falseAnd just as we can test whether two ints are equal using ==, we can use the other equality operator to test of ints are not equal using "!=" (an exclamation followed by an equals sign):
boolean b1 = (1 != 1); // does 1 NOT equal 1? No!
boolean b2 = (1 != 2); // does 1 NOT equal 2? Yes!
System.out.println(b1); // prints false
System.out.println(b2); // prints trueEquality Operators and Booleans
While it may seem strange at first, we can use equality operators to compare two boolean values in the same way that we compare two numeric values. For example:
boolean b1 = (true == true); // does true equal true? Yes!
boolean b2 = (true == false); // does true equal false? No!
System.out.println(b1); // prints true
System.out.println(b2); // prints falseEquality Operators and Doubles
As we noted above, doubles are stored as approximate values. This can lead to very strange behaviors when doubles are combined with equality operators. For example:
double d1 = (28.0 / 7.0) * 7.0;
double d2 = (29.0 / 7.0) * 7.0;
boolean b1 = (d1 == 28.0);
boolean b2 = (d2 == 29.0);
System.out.println(b1); // prints true
System.out.println(b2); // prints false
It is not surprising that b1 is true -- after all, to find d1, we take 28.0, divide it by 7.0, and multiply the result by 7.0. It seems natural that we obtain 28.0 as our result, so we expect (d1 == 28.0) to be true. And so it is!However: when we follow the same logic using 29.0 rather than 28.0, we still expect that (d2 == 29.0), but it does not! Instead, d2 equals 29.000000000000004. This is very close to 29.0, but not exactly 29.0. And so (d2 == 29.0) is false!
Let's see this same example presented slightly differently:
double d = 28.0;
System.out.println(((d / 7) * 7) == d); // prints true
d = 29.0;
System.out.println(((d / 7) * 7) == d); // prints falseSo we see that the expression (((d/7)*7) == d) is true for some values of d and false for others. How confusing! Indeed, it is very confusing and almost always a bad idea to use equality operators with double values. So have this rule:
Rule: Never use equality operators with double values!
Relational Operators
Besides testing for equality or inequality, we can compare numbers based on their order using the relational operators <, >, <=, and >=. For example:
System.out.println(1 < 0); // prints false
System.out.println(1 > 0); // prints true
System.out.println(1 <= 0); // prints false
System.out.println(1 >= 0); // prints true
System.out.println(1 < 1); // prints false
System.out.println(1 > 1); // prints false
System.out.println(1 <= 1); // prints true
System.out.println(1 >= 1); // prints true
System.out.println(1 < 2); // prints true
System.out.println(1 > 2); // prints false
System.out.println(1 <= 2); // prints true
System.out.println(1 >= 2); // prints falseBoolean Operators (aka Logical Operators)
We can also combine boolean values using boolean operators (also called logical operators). You may recall that all logical expressions can be constructed using some combination of AND's, OR's, and NOT's. For this reason, Java includes these three operators: the AND operator (&& -- two ampersands), the OR operator (|| -- two vertical bars), and the NOT operator (! -- an exclamation mark). These work as expected, according to the rules of logic that we previously covered. For example:
System.out.println(true && true); // true AND true is true
System.out.println(true && false); // true AND false is false
System.out.println(false && true); // false AND true is false
System.out.println(false && false); // false AND false is false
System.out.println(true || true); // true OR true is true
System.out.println(true || false); // true OR false is true
System.out.println(false || true); // false OR true is true
System.out.println(false || false); // false OR false is false
System.out.println(!true); // NOT true is false
System.out.println(!false); // NOT false is trueWe can combine equality, relational, and boolean operators in interesting ways. For example:
int n = scanner.nextInt();
boolean isOdd = (n % 2 != 0);
boolean isPositive = (n > 0);
boolean isOddPositive = isOdd && isPositive;
System.out.println(isOddPositive);
This code reads in an integer, and prints out "true" if that integer is both positive and odd (as opposed to even), and false otherwise. Study it carefully.More practice:
- Problem #3: Predict what the following code will print out. Write down your answers. Then (and only then) run the program and compare its output to your answers.
- System.out.println(1 <= 2 + 3 % 4);
- int a=1, b=3;
System.out.println((a < b/2) || (b >= a*3));
- System.out.println(1/2 == 0.5);
System.out.println(1/2 == 0.0);
System.out.println(1/2 == 0);
- int c=5, d=4;
boolean e = (d >= (c - c/d));
boolean f = (d/c == 0.8);
boolean g = (e || f);
System.out.println(e);
System.out.println(f);
System.out.println(g);
System.out.println((!e || f || g) && (!g || f));
- Problem #4: In a recent example, we saw that (n % 2 != 0) evaluates to true if n is odd and false otherwise. Provide 3 different expressions that do the same thing -- that is, that evaluate to true if n is odd and false otherwise. Note that your expressions may be similar to each other, and to the given expression, but they must differ in at least some way. Also note that (n % 2) equals -1 if n is a negative odd number. For some bonus points, provide even more examples of expressions that evaluate to true if and only if a number is odd.
- Problem #5: Briefly explain how the following 4 lines of code demonstrate one of DeMorgan's Laws:
System.out.println(!(true && true) == (false || false));
System.out.println(!(true && false) == (false || true ));
System.out.println(!(false && true) == (true || false));
System.out.println(!(false && false) == (true || true ));
Also, modify the code so that it demonstrates another one of DeMorgan's Laws.
Problem #6: Write Java programs that work as described, except that each print statement may only print out the value of one suitably-named boolean variable.
Write a program that reads in an integer and prints true if that integer is even and false otherwise.
Write a program that reads in an integer and prints true if that integer is divisible by 5 and false otherwise.
Write a program that reads in an integer and prints true if that integer is a positive number that is not divisible by 2, 3, or 5, and false otherwise.
Write a program that reads in two integers and prints out true if exactly one integer is positive and the other is non-positive, and false otherwise. Note that zero is not positive and not negative, but it is non-positive. Here, you may not use an equality operator (==, !=).
Rewrite the preceding program without using boolean operators (&&, ||, !). Instead, use two boolean variables to indicate whether each integer is positive, then use an equality operator (==, !=) to compare these boolean variables.
Problem #7: Write a program that reads in an integer and prints true if that integer represents a leap year and false otherwise. A year is a leap year if it is divisible by 4, except that years divisible by 100 are not leap years unless they are also divisible by 400. So, for example, 1900 was not a leap year because it is divisible by 100 but 2000 was a leap year because, whereas it is divisible by 100, it is also divisible by 400.
Problem #8: Write a program that reads in two doubles and prints true if they are almost equal -- that is, if their difference is less than a very small value, which we will call "epsilon" -- and false otherwise. You can set epsilon equal to 0.00000001. Be sure that your program works whether the larger number is entered first or second. Note that you may not use Math.max, Math.min, or Math.abs, which are methods we will soon learn about and which otherwise would be quite helpful here.
3. Scanning and Printing Doubles and Booleans
We already saw in the examples above that you can print the values of doubles and booleans using System.out.print and System.out.println What about reading these values from the user?
Just as we can use the scanner.nextInt to read ints, we can use scanner.nextDouble to read doubles and scanner.nextBoolean to read booleans. For example:
System.out.print("Enter an integer: ");
int x = scanner.nextInt();
System.out.println("You entered: " + x);
System.out.print("Enter a double: ");
double d = scanner.nextDouble();
System.out.println("You entered: " + d);
System.out.print("Enter a boolean: ");
boolean b = scanner.nextBoolean();
System.out.println("You entered: " + b);
Run this a few times, and try various values for each type of variable. Then answer these questions:
Problem #9: For each of the following, state exactly what occurs, including any exceptions that occur (do not just note that an exception occurs, but list which exception). What happens when...
... scanner.nextInt() scans the value "3.2"?
... scanner.nextInt() scans the value "3.0"?
... scanner.nextDouble() scans the value "3"?
... scanner.nextDouble() scans the value "Infinity"?
... scanner.nextDouble() scans the value "+Infinity"?
... scanner.nextDouble() scans the value "-Infinity"?
... scanner.nextDouble() scans the value "NaN"?
... scanner.nextDouble() scans the value "INFINITY"? (Is it case-sensitive?)
... scanner.nextBoolean() scans the value "TRUE"? (Is it case-sensitive?)
... scanner.nextBoolean() scans the value "1"?
4. The Math Class
So far, we have learned about various math operators, such as +, -, *, /, and %. Java provides even more built-in math functions by way of the Math class. For example, Java provides a method Math.sqrt() that computes the square root of its argument:
System.out.println(Math.sqrt(5)); // prints 2.23606797749979Note that you must preface the method name with "Math." when using these built-in methods in the Math class, so this will not work:
System.out.println(sqrt(5)); // WILL NOT WORK -- must be Math.sqrt(5)Besides useful methods like Math.sqrt, Java also provides two useful constants -- Math.E (Euler's number, the base of the natural logarithm) and Math.PI:
System.out.println(Math.E); // prints 2.718281828459045
System.out.println(Math.PI); // prints 3.141592653589793
What built-in Math methods does Java provide? Here is a table with some of them:
Method Description Math.sqrt Returns the square root of its argument. For example:
System.out.println(Math.sqrt(5)); // prints 2.23606797749979Math.random Returns a random number between 0 (inclusive) and 1 (exclusive). For example:
System.out.println(Math.random());
This prints a different random number every time you run it.Math.min Returns the minimum of its two arguments. For example:
System.out.println(Math.min(3,4)); // prints 3
System.out.println(Math.min(4,3)); // also prints 3
Note that the minimum of two ints is also an int, whereas the minimum of two doubles is a double. So we have:
System.out.println(Math.min(3,4)); // prints 3
System.out.println(Math.min(3.0,4.0)); // prints 3.0 (not 3)Math.max Returns the maximum of its two arguments. For example:
System.out.println(Math.max(3,4)); // prints 4
System.out.println(Math.max(4,3)); // also prints 4
Note that the maximum of two ints is also an int, whereas the maximum of two doubles is a double. So we have:
System.out.println(Math.max(3,4)); // prints 4
System.out.println(Math.max(3.0,4.0)); // prints 4.0 (not 4)Math.abs Returns the absolute value of its argument. For example:
System.out.println(Math.abs(5)); // prints 5
System.out.println(Math.abs(-5)); // also prints 5
Note that the absolute value of an int is also an int, whereas the absolute value of a double is a double. So we have:
System.out.println(Math.abs(5)); // prints 5
System.out.println(Math.abs(-5.0)); // prints 5.0 (not 5)Math.ceil Returns the "ceiling", or the smallest (closest to negative infinity) integer that is greater than or equal to its argument. For example:
System.out.println(Math.ceil(2.01)); // prints 3.0
System.out.println(Math.ceil(2.00)); // prints 2.0
System.out.println(Math.ceil(1.99)); // prints 2.0Note that the value computed by Math.ceil cannot be assigned directly into an integer variable, because the value is actually a double value that happens to be an integer. So:
double d = Math.ceil(1.2); // ok
int x = Math.ceil(1.2); // WILL NOT COMPILEMath.floor Returns the "floor", or the largest (closest to positive infinity) integer that is less than or equal to its argument. For example:
System.out.println(Math.floor(2.01)); // prints 2.0
System.out.println(Math.floor(2.00)); // prints 2.0
System.out.println(Math.floor(1.99)); // prints 1.0Note that the value computed by Math.floor cannot be assigned directly into an integer variable, because the value is actually a double value that happens to be an integer. So:
double d = Math.floor(1.2); // ok
int x = Math.floor(1.2); // WILL NOT COMPILE(int)
Math.roundReturns the rounded integer, or the closest integer value to its argument. For example:
System.out.println(Math.round(2.50)); // prints 3
System.out.println(Math.round(2.49)); // prints 2
System.out.println(Math.round(2.01)); // prints 2
System.out.println(Math.round(2.00)); // prints 2
System.out.println(Math.round(1.99)); // prints 2
Note that, unlike Math.ceil and Math.floor, the value computed by Math.round is not a double. Curiously, it also it not an "int". Instead, it is a "long", which is a special kind of integer. This is a type of variable that we generally do not use. As such, it is recommended that you always convert the result of Math.round from a long to an int, by preceding the call with "(int)", as such:
System.out.println((int)Math.round(2.50)); // prints 3
System.out.println((int)Math.round(2.49)); // prints 2
System.out.println((int)Math.round(2.01)); // prints 2
System.out.println((int)Math.round(2.00)); // prints 2
System.out.println((int)Math.round(1.99)); // prints 2Note that the value computed by Math.round cannot be assigned directly into an integer variable unless you convert it as just described. So:
double d = Math.round(1.2); // ok
int x = (int)Math.round(1.2); // also ok
int y = Math.round(1.2); // WILL NOT COMPILEMath.pow Returns the value of the first argument raised to the power of the second argument. For example:
System.out.println(Math.pow(2,0)); // prints 1.0 (which is 2^0)
System.out.println(Math.pow(2,1)); // prints 2.0 (which is 2^1)
System.out.println(Math.pow(2,2)); // prints 4.0 (which is 2^2)
System.out.println(Math.pow(2,3)); // prints 8.0 (which is 2^3)Note that we can use Math.pow to compute the square root of a number:
System.out.println(Math.sqrt(5)); // prints 2.23606797749979
System.out.println(Math.pow(5,0.5)); // also prints 2.23606797749979Note that the value computed by Math.pow cannot be assigned directly into an integer variable, even when raising an integer to an integer power, because the value is actually a double value that happens to be an integer. So:
double d = Math.pow(1,2); // ok
int x = Math.pow(1,2); // WILL NOT COMPILEMath.exp Returns e (Euler's number, the base of the natural logarithms) raised to the power of its argument. For example:
System.out.println(Math.exp(1)); // prints 2.7182818284590455 (which is E^1)
System.out.println(Math.exp(2)); // prints 7.38905609893065 (which is E^2)Note that we can use Math.pow with the constant Math.E in place of Math.exp:
System.out.println(Math.exp(2)); // prints 7.38905609893065 (which is E^2)
System.out.println(Math.pow(Math.E,2)); // also prints 7.3890560989306495(which is E^2)Note however that double math is approximate, and so computing Math.exp with Math.pow produces very close but not identical results:
double d1 = Math.exp(2);
double d2 = Math.pow(Math.E,2);
System.out.println(d1 == d2); // prints false, they differ
System.out.println(d1 - d2); // prints 8.881784197001252E-16
So we see that the two approaches differ by about one-quadrillionth in this case. They are very, very close. But not identically the same.Math.log Returns the natural logarithm (base e) of its argument. That is, the number x such that ex equals its argument. For example:
System.out.println(Math.log(Math.E)); // prints 1.0 (since e1.0 == e)
System.out.println(Math.log(1)); // prints 0.0 (since e0.0 == 1)
System.out.println(Math.log(0)); // prints -Infinity (since e-infinity == 0)
System.out.println(Math.log(-1)); // prints NaN (since ex is never negative)
You can use this method to compute the logab for any base a by applying this rule:
logab = logeb / logea
For example, the following line prints out the log381, which is the value x such that 3x == 81 (which is 4):
System.out.println(Math.log(81)/Math.log(3)); // prints 4.0 (since 34.0 == 81)
Actually, due to the approximate nature of double math, this prints out 4.000000000000001 rather than 4.0. Close enough!Math.log10 Returns the base-10 logarithm of its argument. That is, the number x such that 10x equals its argument. For example:
System.out.println(Math.log10(100)); // prints 2.0 (since 102.0 == 100)
System.out.println(Math.log10(0.01)); // prints -2.0 (since 10-2.0 == 0.01)
As noted above, you can use Math.log to compute Math.log10, so this method is provided merely as a convenience.Note: in general, you do not need to know much trigonometry for this course. However, we will make simple use of some trig functions in our graphics programs, so these methods are included here mostly for reference purposes. Math.sin
Math.cos
Math.tanThese methods return the trigonometric functions of their argument, which is an angle in radians. For example:
System.out.println(Math.sin(0)); // prints 0.0
System.out.println(Math.cos(Math.PI/3)); // prints (about) 0.5
System.out.println(Math.tan(-Math.PI/4)); // prints (about) -1.0Math.asin
Math.acos
Math.atanThese methods return the inverses of the trigonometric functions -- that is, the "arcsine", "arccosine", and "arctangent". They return an angle in radians. For example, we see how the previous examples are inverted:
System.out.println(Math.asin(0.0)); // prints 0.0
System.out.println(Math.acos(0.5)); // prints (about) π/3
System.out.println(Math.atan(-1.0)); // prints (about) -π/4Math.toDegrees
Math.toRadiansThese methods convert between degrees and radians, where 180 degrees equals π radians.. They are especially useful because many students are more comfortable dealing with degrees than radians. For example:
System.out.println(Math.toDegrees(Math.PI/3)); // prints (about) 60
System.out.println(Math.toRadians(-30)); // prints (about) -π/6
Naturally, these are often used in conjunction with the trigonometric functions. For example:
System.out.println(Math.cos(Math.toRadians(60))); // prints (about) 0.5
System.out.println(Math.toDegrees(Math.acos(0.5))); // prints (about) 60More practice:
- Problem #10: Predict what the following code will print out -- if you cannot state the exact answer due to random behaviors, at least provide the range of possible answers. Write down your answers. Then (and only then) run the program and compare its output to your answers.
- System.out.println(Math.sqrt(Math.sqrt(2) - 2));
- System.out.println(Math.ceil(Math.random()));
- System.out.println(Math.floor(Math.random()));
- System.out.println(100 + 200*Math.random());
- System.out.println(Math.pow(Math.ceil(Math.PI),Math.floor(Math.E)));
- System.out.println((int)Math.round(Math.PI) + (int)Math.round(Math.E));
- System.out.println(Math.exp(Math.abs(Math.floor(Math.E - Math.PI))));
- System.out.println(Math.log(Math.exp(Math.PI)));
- System.out.println((int)Math.round(Math.log10(Math.pow(2,10))));
- System.out.println(Math.toDegrees(Math.PI));
- System.out.println(Math.toRadians(135) / Math.PI);
Problem #11: Write Java programs that work as described.
Write a program that reads in 3 integers and prints out the largest one.
Write a program that reads in 3 doubles and prints out the median (the middle value when the values are sorted).
Hint: find the largest and smallest values (which you should store in variables named "largest" and "smallest" or something similar), and use these to find the median value.
Rewrite your program from a previous problem that determines whether two doubles are almost equal, only here you should use Math.min and/or Math.max to simplify the problem. You may not use Math.abs here.
Rewrite your almost equal program once again, only this time using Math.abs to simplify the problem. You may not use Math.min or Math.max here.
Write a program that reads in 2 doubles and prints out the number of integers that lie between them, inclusively. So if you read in 1.8 and 5.4, you would print out 4, because there are 4 integers in the range [1.8 , 5.4] -- those being 2, 3, 4, and 5. Similarly, if you read in 1.8 and 2.0, you would print out 1 (just the integer 2 is in the range [1.8 , 2.0]). Note that your program must work regardless of the order of the inputs, so if you read in 5.4 and 1.8, you should print out 4, and if you read in 2.0 and 1.8, you should print out 1.
Hint #1: You may want to use Math.max, Math.min, Math.ceil, Math.floor, and (int)Math.round here.
Hint #2: Be sure that your output is an integer and not a double. For example, output 1 and not 1.0.
Write a program that reads in two doubles, which are the length and width of a right triangle, and prints out the length of the hypotenuse of the triangle.
Write a program that reads in the three doubles, which are the lengths of three sides of a triangle, and prints out the area of the triangle using Heron's Formula: A2 = s(s-a)(s-b)(s-c), where a, b, and c are the lengths of the sides of the triangle, and s (the semi-perimeter) equals half the perimeter of the triangle.
Write a program that reads in one double, the radius of a sphere (say in centimeters), and prints out its volume (in cubic centimeters). Note that the volume of a sphere is (4/3)πr3.
Write a program that reads in one double, the volume of a sphere (in cubic centimeters), and prints out its radius (in centimeters).
Hint: Check your work by entering your answer from this problem into the previous problem and verify that you obtain the original volume!
Write a program that reads in two doubles, the radius in kilometers of a planet and its average density in grams-per-cubic-centimeter, and prints out the approximate mass in kilograms of the planet.
Hint #1: There are 1000 grams in a kilogram. Also, there are 100 centimeters in a meter, and 1000 meters in a kilometer, so there are 100,000 centimeters in a kilometer. Thus, there are 100,0003, or 1015 (one quadrillion), cubic-centimeters in a cubic-kilometer.
Hint #2: You may find this table useful:
Planet Density(g/cc) Radius (km)Mercury 5.43 2,440 Venus 5.20 6,051 Earth 5.52 6,378 Moon 3.34 1,738 Mars 3.91 3,397 Jupiter 1.33 71,492 Saturn 0.69 60,268 Uranus 1.32 25,559 Neptune 1.64 24,764 Pluto 2.00 1,160
- According to Isaac Newton, your weight on some planet is proportional to the ratio mplanet/r2. where mplanet is the mass of the planet, and r2 is the square of the radius of the planet. So, if the mass of a planet is twice that of Earth (and the radius is the same as Earth's), then your weight doubles on that planet, whereas if the radius is twice that of Earth (and the mass stays the same as Earth's), then your weight is divided by 4 when visiting that planet. Write a program that reads in two doubles, the radius in kilometers of a planet and its average density in grams-per-cubic-centimeter, and prints out how many times heavier you would be when standing on that planet as compared to standing on the surface of the Earth. We use the letter "g" (lowercase) to represent the force of gravity on the surface of the Earth, so express your answer as a multiple of "g".
Hint #1: start with your solution to the previous problem!
Hint #2: if you enter Earth's radius and density, your program should output "1.0 * g".
Hint #3: find a table on the web that lists your weights on different planets to verify that your program works correctly.
5. The Random Class
While Math.random() may be useful in some cases, Java includes a more powerful collection of random methods in the Random class. For example, this class not only generates random doubles between 0 and 1, but also random integers between 0 and a value of your choosing, and even random booleans (which are great for simulated coin flips!).
In order to use the Random class, however, we need to add a new line of gray code:
public static java.util.Random random = new java.util.Random();
So here is all our gray/green code including this new line:
public class SampleCode {
public static java.util.Scanner scanner = new java.util.Scanner(System.in);
public static java.util.Random random = new java.util.Random();
public static void main(String[] args) {
// place your code here!
}
}
Starting from this gray/green code, here is a simple example that prints out a random double between 0 and 1:
System.out.println(random.nextDouble());Compile this code and run it. You should notice three differences with this new approach:
The Random class requires the new line of gray code;
The Random method is prefaced with "random." rather than "Math." (and the "random" is lowercase whereas "Math" is capitalized); and
This particular Random method is named "nextDouble" whereas the equivalent Math method is named "random"
With that in mind, here are some useful methods from the Random class:
Method Description random.nextDouble This method is basically equivalent to Math.random().
Returns a random number between 0 (inclusive) and 1 (exclusive). For example:
System.out.println(random.nextDouble());
This prints a different random double between 0 and 1 every time you run it.random.nextBoolean Returns a random boolean (true or false). For example:
System.out.println(random.nextBoolean());
This prints either true or false, with equal probability.random.nextInt There are two forms of this method.
The first form takes no argument and returns a random integer between the smallest and largest possible values -- that is, roughly between negative 2 billion and positive 2 billion. For example:
System.out.println(random.nextInt());
The second form takes an argument, and returns a random integer between 0 (inclusive) and its argument (exclusive). This is a very handy method for many tasks. For example:
System.out.println(random.nextInt(6));
This prints out a random number between 0 and 5 (because 6 is exclusive -- it will never occur). Often, we want a random number between 1 and some value. For example, to randomly choose a value when rolling a 6-sided die. For this, we just add 1 to the result, as such:
System.out.println(1 + random.nextInt(6));
This prints out a random number between 1 and 6, as desired.random.setSeed It can be tricky to debug a program that uses random numbers, because its behavior may change every time you run it. Java provides a way around this. You can use the setSeed method to force Java to use the same sequence of random numbers each time you run your program. This method takes one argument, an integer, thus allowing you to try different sequences of numbers that seem random and yet are predictable. For example:
System.out.println(random.nextInt(1000));
System.out.println(random.nextInt(1000));
random.setSeed(0);
System.out.println(random.nextInt(1000)); // always the same!
System.out.println(random.nextInt(1000)); // ditto!Each time you run this, the first two numbers will indeed be random, but the second two numbers will always be the same! Try it a few times to confirm this.
Some practice:
Problem #12: Write Java programs that work as described, except that you may not use Math.random here.
Write a program that prints out a random double between 0 and 5 (exclusive).
Write a program that prints out a random double between 5 and 10 (exclusive).
Write a program that prints out a random integer between 0 and 5 (exclusive).
Write a program that prints out a random integer between 1 and 5 (inclusive, so it can print out 5 sometimes).
Write a program that prints out a random integer between 5 and 10 (inclusive).
Write a program that reads in a positive integer n and prints out a random number between 0 and n inclusive.
Write a program that uses nextBoolean to simulate flipping a coin 3 times, and print out true if all 3 coin flips were heads and false otherwise.
Write a program that uses the form of nextInt that does not take an argument, and call this method 3 times, and print outs true if all 3 random integers are negative. Do you think we could use nextInt in this way to simulate a coin toss?
6. Chars
Besides ints and doubles, Java includes another numeric type, char, that is mainly used to represent characters in Strings. We will use chars much more once we learn about Strings (coming soon!), but here we will begin to study them.
To assign a specific character to a char variable, we enclose that character in single-quotes (not double-quotes), like this:
char c1 = 'A'; // assigns uppercase-A to variable c1
char c2 = 'B'; // assigns uppercase-B to variable c2
char c3 = 'a'; // assigns lowercase-a to variable c3
System.out.println(c1); // prints A
System.out.println(c2); // prints B
System.out.println(c3); // prints a
Chars are special kinds of integers, actually, so we can compare chars using equality and relational operators. The comparison works alphabetically, so 'A'<'B', except that all uppercase letters occur before any lowercase letters, to 'B'<'a', as we see here:
char c1 = 'A';
char c2 = 'B';
char c3 = 'a';
System.out.println(c1 < c2); // prints true, as 'A' < 'B'
System.out.println(c1 < c3); // prints true, as 'A' < 'a'
System.out.println(c3 < c2); // prints false, as 'B' < 'a'
Not only are chars special kinds of integers, we can even find the specific integer value assigned to any particular character. Java uses Unicode, which is a code that converts characters to numbers. The Unicode value for 'A' is 65, 'B' is 66, 'C' is 67, and so forth. Lowercase 'a' is 97, 'b' is 98, 'c' is 99, and so on. We can see the Unicode values of chars by first assigning those chars into integers and then printing them out, like this:
int i1 = 'A'; // we are assigning the char 'A' into an integer variable
int i2 = 'B'; // same for 'B'
int i3 = 'a'; // same for 'a'
System.out.println(i1); // prints 65, the Unicode value of 'A'
System.out.println(i2); // prints 66, the Unicode value of 'B'
System.out.println(i3); // prints 97, the Unicode value of 'a'
Even though we can find the Unicode values for chars, we very rarely need them. For example, say we need to check if a character is an uppercase letter. This is true if its Unicode value is at least 'A' (65) and not greater than 'Z' (90). We can perform this check as follows:
((c >= 'A') && (c <= 'Z')) // evaluates to true if c is an uppercase letter and false otherwise
Here we will use this code to confirm that 'A' is an uppercase letter and 'a' and '$' are not uppercase letters:
char c = 'A';
System.out.println((c >= 'A') && (c <= 'Z')); // prints true, as 'A' is uppercase
c = 'a';
System.out.println((c >= 'A') && (c <= 'Z')); // prints false, as 'a' is not uppercase
c = '$';
System.out.println((c >= 'A') && (c <= 'Z')); // prints false, as '$' is not an uppercase letter
Note that this code does not require that we know the actual values assigned to 'A' or 'Z'.Some practice:
- Problem #13: Predict what the following code will print out. Write down your answers. Then (and only then) run the program and compare its output to your answers.
Hint: The Unicode value of the character '0' (zero) is 48.
- char c = 'D';
int i = c;
System.out.println(c);
System.out.println('D');
System.out.println(i);
- System.out.println('z' > 'A');
System.out.println('Z' > 'a');
- int i = '0';
System.out.println(i);
i = '1';
System.out.println(i);
i = '2';
System.out.println(i);
- int i = 'Z';
System.out.println(i);
i = 'z';
System.out.println(i);
i = '9';
System.out.println(i);
- System.out.println('5' < 'A');
System.out.println('5' < 'a');
- char c1 = '2';
char c2 = '5';
int i1 = (c1 - '0');
int i2 = (c2 - '0');
int i = 10*i1 + i2;
System.out.println(i1);
System.out.println(i2);
System.out.println(i);
- Problem #14: Write Java programs that work as described. For each program, you will first assign some value to a variable 'c' of type char. Your program must work for any value assigned to that variable.
Write a program that prints true if c is either an uppercase or a lowercase letter, and false otherwise.
Write a program that prints true if c is a decimal digit (that is, one of '0', '1', '2', ... , '9') and false otherwise.
Write a program that prints true if c is a hexadecimal digit and false otherwise. The hexadecimal digits include all the decimal digits ('0', '1', ..., '9'), but also include the first 6 letters (from 'A' to 'F' for uppercase, or from 'a' to 'f' for lowercase).
7. Other Primitive Types
So now we know about ints, doubles, booleans, and chars. In Java, these are called primitive types. This is because while they have a value, we cannot use them to call any methods. By contrast, a reference type can be used to call certain methods defined for that type. We have already seen some reference types. Consider the scanner -- we can use that object to call the nextInt() and nextDouble() methods among others. Or consider the page variable in our graphics programs --- we can use that object to call the fillRect() and setColor() methods among others. With primitive types, however, we cannot call any methods on them. So we cannot have code like this:
double d1 = 5;
double d2 = d1.sqrt(); // Will not compile!
This code will not work because d1 is not an object, but a primitive type, and so we cannot call any methods on it. Of course, we can compute the square root of d1, but we do it like this:
double d1 = 5;
double d2 = Math.sqrt(d1);
Here, we are not calling a method on d1, but providing the value of d1 as an argument to a method. Be sure you understand this distinction!
Are there other primitive types? Yes. In fact, there are 8 primitive types in Java: ints, doubles, booleans, chars, bytes, shorts, longs, and floats. The AP exam only covers the first four types (ints, doubles, booleans, and chars), but you should be familiar with all 8 types, so we will describe them here:
Type
AP? Description
Size Min Max int yes integers between -2 billion and +2 billion. 4 bytes
(32 bits)Integer.MIN_VALUE
= -231 = -2147483648
(about -2 billion)Integer.MAX_VALUE
= 231-1 = 2147483647
(about +2 billion)double yes floating-point numbers with a huge range. 8 bytes
(64 bits)-Double.MAX_VALUE
= -1.7976931348623157E308
(about -1.8 x 10308).
Also, smallest positive is:
Double.MIN_VALUE
= 4.9E-324
(about 5 x 10-324)Double.MAX_VALUE
= 1.7976931348623157E308
(about +1.8 x 10308).
Also, largest negative is:
-Double.MIN_VALUE
= -4.9E-324
(about -5 x 10-324)boolean yes true or false values 1 byte
(8 bits)n/a n/a char yes characters (like 'A' or 'z' or '&')
(Technically: the integer Unicode values representing characters, with values between 0 and +65535.)2 bytes
(16 bits)Character.MIN_VALUE
= 0Character.MAX_VALUE
= 216-1 = +65535
(about 65 thousand)byte no integers between -128 and +127 1 byte
(8 bits)Byte.MIN_VALUE
= -27 = -128Byte.MAX_VALUE
= 27-1 = +127short no integers between -32768 and +32767 2 bytes
(16 bits)Short.MIN_VALUE
= -215 = -32768Short.MAX_VALUE
= 215-1 = +32767long no integers between -9 billion billion and
+9 billion billion.8 bytes
(64 bits)Long.MIN_VALUE
=-263
= -9223372036854775808
= about -9 billion billionLong.MAX_VALUE
= 263 - 1
= 9223372036854775807
= about +9 billion billionfloat no floating-point numbers, like doubles, only with less accuracy 4 bytes
(32 bits)-Float.MAX_VALUE
= -3.4028235E38
(about -3.4 x 1038).
Also, smallest positive is:
Float.MIN_VALUE
= 1.4E-45
(about 1.4 x 10-45)Float.MAX_VALUE
= 3.4028235E38
(about +3.4 x 1038).
Also, largest negative is:
-Float.MIN_VALUE
= -1.4E-45
(about -1.4 x 10-45)This may be daunting at first, but a few observations make it much easier to digest:
Booleans are not numeric.
Booleans can only be true or false, and not a number -- and all the other primitive types are numbers.Only floats and doubles are non-integer numeric primitives.
All other numeric types are restricted to integers.The only unsigned integer type is char.
There are no negative char's, so we say they are unsigned. All other numeric types are signed -- they include both positive and negative values.We can find the min/max values with these rules:
Signed values (all but char's) use 1 bit for the sign (positive or negative).
So a k-bit signed value must use 1 bit for the sign, leaving (k-1) bits for the values.Unsigned values (just char's) do not use an extra bit for the sign
So a k-bit unsigned value can use all k bits for the value.Even though 0 is not positive or negative, it is included with the positives.
So there is one extra negative value than positive values in signed numerics.k bits can have 2k different values.
Hence, we have these rules for integer types:
k unsigned bits range from 0 to 2k-1.
k signed bits range from -2(k-1) to +2(k-1)-1.
We can apply these rules to each integer type like this:
Bytes are 8-bit signed numerics, so k=8, and they range from -27 to +27-1.
Shorts are 16-bit signed numerics, so k=16, and they range from -215 to +215-1.
ints are 32-bit signed numbers, so k=32, and they range form -231 to +231-1.
Longs are 64-bit signed numbers, so k=64, and they range form -263 to +263-1.
Chars are 16-bit unsigned numerics, so k=16, and they range from 0 to +216-1.
Some practice:
Problem #15: Predict what the following code will print out. Write down your answers. Then (and only then) run the program and compare its output to your answers.
Some of these results may be surprising to you -- be sure you take the time to understand why they work as they do!
int iMin = Integer.MIN_VALUE;
int iMax = Integer.MAX_VALUE;
System.out.println(iMax + 1); // overflow!
System.out.println((iMax + 1) == iMin);
System.out.println(iMin - 1); // also overflow!
System.out.println((iMin - 1) == iMax);
System.out.println(iMax + iMin);
double dMax = Double.MAX_VALUE;
System.out.println((dMax + 1.0) == dMax); // overflow
System.out.println((dMax * 2.0) == Double.POSITIVE_INFINITY); // another kind of overflow
double dMin = Double.MIN_VALUE;
System.out.println((dMin / 2.0) == 0.0); // underflow
int minC = Character.MIN_VALUE;
int maxC = Character.MAX_VALUE;
System.out.println(minC);
System.out.println(maxC);
System.out.println(Byte.MIN_VALUE);
System.out.println(Byte.MAX_VALUE);
System.out.println(Short.MIN_VALUE);
System.out.println(Short.MAX_VALUE);
System.out.println(Long.MAX_VALUE > Integer.MAX_VALUE);
System.out.println(Long.MIN_VALUE < Integer.MIN_VALUE);
System.out.println(Double.MAX_VALUE > Float.MAX_VALUE);
System.out.println(Double.MIN_VALUE < Float.MIN_VALUE);
8. Converting Types
We often must convert between different numeric types, say converting a char into an int, or an int into a double. Here we discuss the various types of conversions, and how to perform them.
Widening versus Narrowing Conversions
As we saw, chars can be between 0 and +65535, and ints can be between about -2 billion and +2 billion. Thus, we can convert any legal char value into a legal int value. For example:
char c = 'A'; // assigns a char value (65, to be exact)
int i = c; // converts the char into an int
System.out.println(i); // prints 65
Great! However, the opposite is not true -- there are many legal int values that are illegal char values. For example, say we are converting the int value -5 to a char. Seeing as the smallest char value is 0, this is impossible. So the compiler will not let you do it! Here is the code that shows this failure:
int i = -5; // assigns an int value
char c = i; // fails to convert the int into a char (will not compile)
System.out.println(c);
In fact, this code will fail for any value assigned to the int variable, even if it within the legal range of a char. For example:
int i = 'A'; // assigns an int value (65, which is a legal char value)
char c = i; // STILL fails to convert the int into a char (will not compile)
System.out.println(c);
So we see that the compiler will convert chars into ints, but it will not convert ints into chars.
Because every char value is a legal int value, we say that ints are wider than chars (or, if you prefer, that chars are narrower than ints). A conversion from a narrower type to a wider type is called a widening conversion (and the other way around is a narrowing conversion).
The key: Java will automatically perform widening conversions, but will not automatically perform narrowing conversions.
So: which conversions are widening, and which are narrowing? We already saw that chars are narrower than ints, because some legal int values are not legal char values. To answer this question, we will construct the following table which shows the ranges for each primitive numeric type:
value double float long int char short byte -1.8 x 10308 -3.4 x 1038 about -9 billion billion about -2 billion -32768 -128 0 +127 +32767 +65535 about +2 billion about +9 billion billion +3.4 x 1038 +1.8 x 10308 This table clearly shows which types are narrower than other. A type is narrower than a second type if it is missing a bar in this table where the second type has a bar. From this, we see that:
doubles are wider than all other types
floats are wider than all other types except doubles
longs are wider than all other types except floats and doubles
ints are wider than chars, shorts, and bytes
chars are not wider than any other type!
shorts are wider than bytes (but not chars)
bytes are not wider than any other type!
One surprising result is that two types can each be narrower than the other! For example, chars are narrower than bytes but bytes are also narrower than chars.
Types of Conversions
Here we cover the four different ways in which primitive type conversions may occur.
1) Assignment Conversions
An assignment conversion occurs when we assign a value of one type into a variable of another type. For example:
int i = 5;
double d = i; // Assignment conversion!
This example converts the integer 5 into the double 5.0 and then assigns that value (5.0) to the double d.
Assignment conversions must be widening conversions (such as from int to double). Assignment conversions cannot be narrowing conversions (such as from doubles to ints). For example:
double d = 5.0;
int i = d; // Fails: narrowing assignment conversion
2) Method Invocation ConversionsA method invocation conversion occurs when we assign an argument of one type to a parameter of another type in a method call. For example:
int i = 5;
double d = Math.sqrt(i); // Method invocation conversion!
This example assigns the integer value 5 to the only parameter of the Math.sqrt method, but that method expects its argument to be a double, so Java first converts the integer (5) into a double (5.0), and then calls the method.Method invocation conversions must be widening conversions (such as from int to double). Method invocation conversions cannot be narrowing conversions (such as from doubles to ints). For example:
page.fillRect(0,0,10,20.5); // Fails: narrowing method invocation conversion
The fillRect method expects 4 integers for the left, top, width, and height. Here, we provided a double for the height, and doubles are wider than integers, so this fails.
3) Promotion Conversions
A promotion conversion occurs when we perform arithmetic on values with different types. For example:
double d = 1.5 + 2; // Promotion conversion!
To add 1.5 (a double) and 2 (an integer), Java first makes these values have the same type by promoting 2 from an integer to a double, then adding 1.5 and 2.0, the result of which is a double. Notice that there is no assignment conversion here -- the right-hand-side is already a double before it is assigned to the double
Because Java always promotes the narrower type to the wider type, promotion conversions are always widening conversions (such as from int to double).
4) Casting Conversions
The previous three cases are all automatic: when necessary, Java automatically performs a widening conversion. What about narrowing conversions? Java will never perform these automatically. But sometimes we must perform a narrowing conversion. In this case, we must explicitly direct the compiler to do the conversion by casting to the narrower type. For example:
double d = 5.0;
int i = (int) d; // Legal narrowing conversion with casting
System.out.println(i); // prints 5
This example compiles and runs without errors. How does it work? On the second line, we precede the value d with "(int)" -- that is, the type int enclosed in parentheses. This awkward syntax is how we cast the double into an int. The result of (int)d is an int where the double d has been truncated. That is, its value after the decimal point is simply ignored. For example:
System.out.println((int)4); // prints 4 (not 4.0)
System.out.println((int)4.9); // prints 4 (not 5)
System.out.println((int)4.5); // prints 4 (not 5)
System.out.println((int)-4.9); // prints -4
Here we see that casting to an integer is not the same as rounding, nor taking the floor nor ceiling. In all cases, casting to an integer will simply truncate a value after the decimal point.What happens if we cast a value that is out of range? For example:
System.out.println((byte)200); // overflow! prints -56
Here, we try to cast the value 200 from an int into a byte, but the largest byte is +127. This is a case of overflow, and so the result is bogus. In this case, the bogus result happens to be -56 (which, of course, is not equal to 200). In general, if you cast a value that is outside the range of the target type, the result will be incorrect.
As an aside, we now can understand why we use "(int)" in a call to Math.round. It turns out that Math.round is the only Math method that takes a double parameter and yet returns a long result. Since converting a long into an int is a narrowing conversion, we cannot do this automatically, so we must cast the result to an int. This is precisely what we do when we precede the call with "(int)", as such:
int i = (int)Math.round(2.50); // rounds 2.5 to the long 3, then casts to the int 3
System.out.println(i); // prints 3Illegal Conversions
There are some conversions that Java will not perform, even with casting. In particular, Java will not convert between boolean values and numeric values. For example:
boolean b = true;
int i = (int) b; // Fails: illegal conversion from boolean to int
Here, we try to convert the boolean value "true" into an integer value. We may think this is reasonable (and may expect, say, a value of 1 as a result), but Java will not let us do this.
Other ConversionsConverting character digits to ints
While not strictly conversions in the technical sense, there are other ways in which we may wish to change primitive types. For example, say we have a char value that we know is a decimal digit ('0', '1', ..., '9'), and we wish to convert it into that decimal value. This is not the same as directly converting the char into an int, because in that case (as we have already seen) we will obtain the Unicode value for that character. That is:
char c = '0';
int i = c;
System.out.println(i); // prints 48
This prints 48, not 0, because 48 is the Unicode value for the character '0'. To convert to the decimal value 0, we must subtract the Unicode value of '0' (that is, 48). So we have:
char c = '0';
int i = c - '0';
System.out.println(i); // prints 0
This seems to work. Let's try it with the character '3', which has Unicode value 51:
char c = '3';
int i = c - '0';
System.out.println(i); // prints 3
This prints out 3, and not 51. So we conclude that we can find the decimal value of a character digit by subtracting '0' and converting to an int.Converting uppercase to lowercase
As another example, here we convert an uppercase letter to its lowercase equivalent. This is not a conversion, technically, because we start and end with a char. Now, because 'A' is 65 and 'a' is 97, we may observe that we just need to add their difference, or 32, to any uppercase letter to get its lowercase equivalent. However, we wish to do this without using the actual Unicode values, so instead we express the difference as ('a' - 'A'). This is still 32, but does not require us to know that value. So we have:
char c1 = 'A';
char c2 = c1 + ('a' - 'A'); // fails: illegal narrowing conversion from int to char
System.out.println(c2);
This code will not compile! What went wrong? On the second line, when we add c1 and ('a' - 'A'), even though all the values are chars, the result of the operation is an int. The compiler will not automatically convert this int back into a char when assigning the value to c2. Fortunately, we know what to do about this: we simply cast the result back into a char, like this:
char c1 = 'A';
char c2 = (char)(c1 + ('a' - 'A')); // converts uppercase into lowercase
System.out.println(c2); // prints 'a'
This seems to work. Let's try it with uppercase 'Q':
char c1 = 'Q';
char c2 = (char)(c1 + ('a' - 'A')); // converts uppercase into lowercase
System.out.println(c2); // prints 'q'
This prints out q, as desired. So we conclude that we can convert from uppercase to lowercase by adding ('a' - 'A') and casting the result to a char.
Converting booleans to ints
As a final example, we noted that it is illegal to convert from booleans to ints, even with casting. Yet there are times when we wish to do precisely this. In this case, we can make use of the tertiary operator (?:). This is a strange syntax, and your use of it should be limited. But here is an example that uses the tertiary operator to convert boolean values into integers, using 0 for false and 1 for true:
boolean b = true;
int i = (b ? 1 : 0); // uses tertiary operator to convert boolean to int
System.out.println(i); // prints 1
b = false;
i = (b ? 1 : 0); // once again, now converting false to 0
System.out.println(i); // prints 0
In general, the tertiary operator takes a boolean value followed by two other values. If the boolean is true, the operator evaluates to its second value, otherwise it evaluates to its third value. From this, you should understand how the given example works. Again, you should use this operator sparingly, if at all.
Some practice:
Problem #16: Predict what the following code will print out. Write down your answers. Then (and only then) run the program and compare its output to your answers.
Some of these examples will not compile. Indicate those cases, along with why they will not compile.
int i = 32;
char c = 'A' + i;
System.out.println(c);
int i = ((Math.sqrt(10) < 3) ? 123 : 456);
System.out.println(i);
int i = 11;
double d = i/2.0;
System.out.println(d);
d = i/2;
System.out.println(d);
char c = 'A';
double d = c/2;
int i = (int)Math.floor(d);
System.out.println(c);
System.out.println(d);
System.out.println(i);
double d = 5.9;
int i = Math.round(d);
System.out.println(i);
double d1 = 5.9;
double d2 = (double)(int)d1;
System.out.println(d1);
System.out.println(d2);
System.out.println(d1 == d2);
System.out.println(6 / 16 / 4.0);
System.out.println(6 / (16 / 4.0));
System.out.println((int)6 / (16 / 4.0));
System.out.println((int)(6 / 16 / 4.0));
System.out.println((int)(6 / (16 / 4.0)));
Problem #17: Write Java programs that work as described.
Write one line of Java that demonstrates assignment conversion, promotion conversion, and casting (all three of these on the same line) -- and clearly label each.
Write a Java program that reads an int and converts it into a variable of type boolean. You may assume 0 is false and all other values are true. Print the value of the boolean.
Write a program that reads an int representing a Unicode value and converts it into a variable of type char. Print the value of the char. So if your program reads in 65, it should print out uppercase 'A'.
Write a program that reads an int between 0 and 9, inclusive, and converts it into a variable of type char -- the character digit equivalent of the input. Print out both the value of the char as well as its Unicode value. So if your program reads in 0, it should print out the char '0' followed by the value 48.