BBC (Brian's Boot Camp)

Not to be confused with the British Broadcasting Corporation, the BBC will focus on Brian's fast paced journey of the mastery of the Java programming language.

Tuesday, February 15, 2005

Integer questions re: 2 exercises

So I managed to get up nice and early and put some good time in. I got through some 21 Days and spent some time writing some pseudocode for the "Final Countdown" assignment. I may spend lunch today focusing on that assignment since I think I have it worked out at least in my head.

But I ran into some questions about the two exercises in the chapter this morning. In both cases, I was able to fulfill the exercise, but I got slightly different results and/or couldn't use integer types that I thought I should have been able to use.

Rather than make this post super long, I'll leave it at that and post comments to this post for each of the two exercises.

3 Comments:

Blogger Brian T. Grant said...

Well this is very aggrivating. Blogger supports all sorts of tagging when you make a post to the main page, but almost none for comments. So, while this should have looked very nice, I'll just look like crap instead.

Exercise #1:
Create a program that calculates how much a $14,000 investment would be worth if it increased in value by 40% during the first year, lost $1,500 in value the second year, and increased 12% in the third year.

This is what I eventually came up with; i.e. without any compiler errors:
public class FinancialCalc {
public static void main(String[] arguments) {
double dough = 14000;

System.out.println("The initial investment is $" + dough + ".");
dough = dough * 1.4;
System.out.println("The investment increased by 40% during the first year yeilding $" + dough + ".");
dough = dough - 1500;
System.out.println("The investment lost $1,500 during the second year yeilding $" + dough + ".");
dough = dough * 1.12;
System.out.println("The investment increased by 12% during the third year yeilding $" + dough + ".");
}
}

Here are some issues I ran into:
1) At first I used an int rather than a double. I figured, "based on the numbers I'm working with, the range offered by a short should be sufficient. When I compiled, I got the following error:
FinancialCalc.java:6: possible loss of precision
found : double
required: short
dough = dough * 1.4;
^
FinancialCalc.java:8: possible loss of precision
found : int
required: short
dough = dough - 1500;
^
FinancialCalc.java:10: possible loss of precision
found : double
required: short
dough = dough * 1.12;
^
3 errors

At that point, I figured the errors had to do with multiplying a short by a floating-point number in two of the lines. So I changed the short to a float. That time around, I got this error:
FinancialCalc.java:6: possible loss of precision
found : double
required: float
dough = dough * 1.4;
^
FinancialCalc.java:10: possible loss of precision
found : double
required: float
dough = dough * 1.12;
^
2 errors

At this point, I wasn't sure why there was a problem since I declared dough to be a float. Finally, I declared dough as a double (you can't go any bigger, I guess). While that compiled, it seemed unsatisfying that I had to grab the biggest available integer type in order to make it work. So I went to look at the author's example:
class Invest {
public static void main(String[] arguments) {
float total = 14000;
System.out.println("Original investment: $" + total);
// Inceases by 40 percent the first year
total = total + (total * .4F);
System.out.println("After one year: $" + total);
// Loses $1,500 the second year
total = total - 1500F;
System.out.println("After two years: $" + total);
// Increases by 12 percent the third year
total = total + (total * .12F);
System.out.println("After three years: $" + total);
}
}

So, what I see is that he's "forced" all of the calculations to be literal floats. I guess I'm not entirely sure why that would be necessary unless, if you don't specify, Java just assumes that a number is as big as it can be. Reading his code, too, I suppose there is no reason to make my class public since nothing else is going to be reading it, right?

Thus ends my first post. Will get to Ex. #2 later today

11:03 AM  
Blogger Brian T. Grant said...

Now that I look at it, I think the compiler errors on exercise two were for the same reason as #1, but I'll post it anyway:
Write a program that displays two numbers and uses the / and % operators to display the result and remainder after they are divided. Use the \t character escape code to separate the result and remainder in your output.My final code ended up this way:
public class NumberDisplay {
public static void main(String[] arguments) {
int numOne = 15;
int numTwo = 5;
int answerResult = 0;
int answerRemainder = 0;

// Display both numbers.
System.out.println("The two numbers are " + numOne + " and " + numTwo + ".");
answerResult = numOne / numTwo;
answerRemainder = numOne % numTwo;
System.out.println(answerResult + "\t" + answerRemainder);
}
}
Again, I'm sure I didn't need to make it public. But here again, I had initially started out using a byte rather than an int since the numbers I was working with were so small. This time, too, there were errors about potential loss of precision. I changed all the bytes to ints and it was fine.

This time, in his example, he isn't declaring literals, but he's using floats from the beginning. Here is his code:
class Divide {
public static void main(String[] arguments) {
float number1 = 15;
float number2 = 6;
float result = number1 / number2;
float remainder = number1 % number2;
System.out.println(number1 + " divided by " + number2);
System.out.println("\nResult\tRemainder");
System.out.println(result + "\t" + remainder);
}
}
I'm beginning to wonder why you would ever use anything smaller than a float if -- and it just seems like this at the moment -- that you can't do very much math unless you use something that large. And I can't figure why you'd need to use anything so large unless it has something to do with the way Java handles math.

12:21 PM  
Blogger Sten said...

1) Your question about whether to maker your classes public:

You have the right idea, if a class is not called (or shouldn't be called) by another class, it should, generally, be private. However, you need at least one public class in your program so the JVM can call the main() method. Think of the JVM as an external caller.

2) Your precision questions.

You've more or less answered your precision questions as your comments went on, but let me clarify it all here.

It's admirable that you are trying to find the smallest data type to fit your needs. It tells me you're coming from the old school C mentality of memory being at a premium (not surprisingly considering your unix background). Indeed, much of what you wrote with shorts and bytes and floats would compile without warning using a C compiler.

However, Java is a strongly typed language and here are the rules and consequences of that:

1) When doing math operations, your answer has to be at least as "wide" as the widest operand. So if you're dividing a byte by a double, your answer has to be a double.

2) Integer math operations (operations on non-floating point numbers) have to be at least as wide as "int". So you can divide two bytes, but your answer must be an int.

Now why is this? Mostly to prevent loss of precision (hence your compiler errors). If you multiply a byte by a byte, you could potentially overrun the size of a byte. Likewise if you divide an int by a float, you could be left with a remainder, so you'll be forced to 'upgrade' your answer from an 'int' to a floating point type. In a weakly typed language like C, if the data type wasn't big enough to hold the result, it would store garbage, not complain about it, and leave you with unpredictable results.

In general you will always want to use doubles for floating point operations and integers for, well, interger operations. Don't think of double as being able to hold twice a big of a number as float, rather think of it as twice as precise -- and you always (with rare exception) want the most precision you can afford -- regardless of the size of the result.

I initially only used floats in Iris when doing math operations on hours, since they never went beyond two decimal places. Sure enough though, on reports adding thousands of rows of floats together, I started to get rounding errors. I switched it to doubles, and the rounding errors went away.

It doesn't have to be a large number of operations to show off cumulative rounding errors though. Money is a perfect example. When writing the accounting system here, I wrote a custom class (called Money) as a wrapper around a BigDecimal -- not even double was precise enough. But it's just money you say, it's just two decimal places. It's all about how CPUs do floating point arthimatic. It's all approximations.

I've got a meeting now, but I want to push this out. We can keep the conversation going if you want more info...

1:54 PM  

Post a Comment

<< Home