Variable Values in Java - java

I have a quick question in regards to the value of how variable values work. I am working on a program right now, which looks like this:
public void run() {
println("There are " + ATOMS + " initially.");
int atoms = ATOMS;
int year = 0;
while (atoms > 0) {
for (int i = atoms; i > 0; i--) {
println(i);
if( rgen.nextBoolean() ) {
atoms--;
println("The total atoms is " + atoms);
}
println("The total for i is " + i + "\n" );
}
year++;
println("There are " + atoms + " at the end of year " + year );
}
}
At the part with the for loop, and setting the variable i to the value of atoms, is what has me confused. Lets say the value of atoms starts at 20. It goes through the for loop and lets assume that the first time through the RandomGenerator makes it true. So that subtracts 1 from atoms. Then after that the value of i should also be minused due to the i--. So my question is: When I set the variable i to the value of atoms does that just take i and set it to the initial value of 20? And then from there every time I adjust the value of i it is taking off of its own version of 20, and then when I change the value of atoms it, too has its own value. So when I subtract from atoms, that is not also being subtracted from i? That is the only way I can make sense of it because this program is written and works correctly, but that part has me confused.
Thank you very much in advance for any help!

yes you have answered your own question. the variable i and atoms are two separate instances.
when you start the loop you are setting i equal to the same value as atoms but they are still separate variables. therefore inside the loop when you change the value of one it does not affect the other.

Once you set the value of i=atoms, it no longer changes. It is the loop initializer, and will no longer be processed.
"i" of course will be decremented continuously (because of the i-- decrement).
But you can change the value of atoms to whatever and the results will not change.

i=atoms is the initialization in the for loop. So then on, value of i independent of atoms.

Related

What would cause a for loop to decrement when it's supposed to increment?

I wrote a method to calculate how long ago a father was twice as old as his son and in how many years from now this would be true. Unexpectedly, it returns "-2 years ago" for an 8-year-old father and a 3-year-old son. Equally unexpectedly, it returns "-1 years from now" for a 3-year-old father and a 2-year-old son. I am not concerned about how to improve the code because I already know how to do this. Instead, I am puzzled about why the for loop counter appears to be decrementing when it's supposed to increment.
Here is my code.
public class TwiceAsOld {
public static void twiceAsOld (int currentFathersAge, int currentSonsAge) {
int yearsAgo;
int yearsFromNow;
int pastFathersAge = currentFathersAge;
int pastSonsAge = currentSonsAge;
int futureFathersAge = currentFathersAge;
int futureSonsAge = currentSonsAge;
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge; yearsAgo++) {
pastFathersAge--;
pastSonsAge--;
}
System.out.println("The father was last twice as old as the son " + yearsAgo + " years ago.");
for (yearsFromNow = 0; futureFathersAge != 2 * futureSonsAge; yearsFromNow++) {
futureFathersAge++;
futureSonsAge++;
}
System.out.println("The father will be twice as old as the son in " + yearsFromNow + " years from now.");
}
public static void main(String[] args) {
twiceAsOld(8, 3);
twiceAsOld(3, 2);
}
}
With twiceAsOld(8, 3), the for loop's increment appears to have reversed itself to count down from 0 instead of up. With twiceAsOld(3, 2), the -1 might stand for an error indicating that the father has never been twice as old as his son and never will be. What I don't understand is what would cause a for loop to start decrementing the i value when it's supposed to increment. I was expecting the counter to increment indefinitely until the program ran out of memory.
I already know how to improve this program, but I am curious about how the counter in a for loop can decrease when it's supposed to increase. Can anybody explain this?
(UPDATE: Thanks everyone for your answers. I can't believe I forgot about integer overflow. I tried making the variables longs instead of integers, but this made the program even slower. Anyway, now I realize that the counter was incrementing all along until it overflew and landed at a negative value.)
It became negative because that is what happens in Java when an int calculation overflows.
Take a look at
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
It says that
If an integer addition overflows, then the result is the low-order bits of the mathematical sum as represented in some sufficiently large two's-complement format. If overflow occurs, then the sign of the result is not the same as the sign of the mathematical sum of the two operand values.
Didn't you notice that your program runs quite slowly? :)
For the (8, 3) years ago case, your for loop keeps looping and looping, trying to find a year that the father is twice as old, but as we know, the father will only become twice as old in the future, but not in the past. The for loop doesn't know this and it will try very hard to find such a year. It tries so hard that yearsAgo is incremented past the max value of int. This causes an overflow, and the value of yearsAgo will "wrap back around" to the minimum value of int, which is a negative number. And then this negative number will get incremented many many times, until -2.
The same goes for the other case.
To fix this, you can add if statements to check if the results are negative:
public static void twiceAsOld (int currentFathersAge, int currentSonsAge) {
int yearsAgo;
int yearsFromNow;
int pastFathersAge = currentFathersAge;
int pastSonsAge = currentSonsAge;
int futureFathersAge = currentFathersAge;
int futureSonsAge = currentSonsAge;
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge; yearsAgo++) {
pastFathersAge--;
pastSonsAge--;
}
// Here!
if (yearsAgo >= 0) {
System.out.println("The father was last twice as old as the son " + yearsAgo + " years ago.");
}
for (yearsFromNow = 0; futureFathersAge != 2 * futureSonsAge; yearsFromNow++) {
futureFathersAge++;
futureSonsAge++;
}
if (yearsFromNow >= 0) {
System.out.println("The father will be twice as old as the son in " + yearsFromNow + " years from now.");
}
}
You can also stop the loop when it reaches negative values to make your program faster:
for (yearsAgo = 0; pastFathersAge != 2 * pastSonsAge && yearsAgo >= 0; yearsAgo++) {
When I debug your code I can see that yearsAgo is incrementing without bound, causing pastFathersAge and pastSonsAge to go into negatives. This is causing negative integer overflow. This happens because your condition pastFathersAge != 2 * pastSonsAge is never met (rather, never NOT met). Not until your futureFathersAge has gone all the way through the negatives, back into positives, and finally settles on -2.
The moral of the story is to make certain that your terminating condition for your loop can always can be met. Don't use !=, use >= or <= instead.

java - Random inside while loop causes infinite loop with all same numbers

On the Programming By Doing website I'm stuck on the DoubleDice exercise. It's supposed to run a while loop until you come up with the same value for each dice (doubles - 3 and 3, 4 and 4, etc.)
I've input what I think to be the correct code, but I get this infinite loop that prints out the exact same "randoms" every time through the while loop.
I've pondered this for about a day and decided to give it to SO.
Thanks.
import java.util.Random;
public class diceDoubles {
public static void main(String[] args){
Random dice = new Random();
int roll1 = 1 + dice.nextInt(6);
int roll2 = 1 + dice.nextInt(6);
System.out.println("HERE COMES THE DICE!\n");
while(roll1 != roll2) {
System.out.println("Die 1: " + roll1);
System.out.println("Die 2: " + roll2);
System.out.println("The total is " + (roll1 + roll2) + "\n");
}
}
}
You need to add "variables roll1 and roll12 update code" to while loop, like this:
while(roll1 != roll2) {
roll1 = 1 + dice.nextInt(6);
roll2 = 1 + dice.nextInt(6);
System.out.println("Die 1: " + roll1);
System.out.println("Die 2: " + roll2);
System.out.println("The total is " + (roll1 + roll2) + "\n");
}
Spend some time familiarizing yourself with the control flow of the code, and what each statement does.
<type> <identifier>;
Lines like this DECLARE a variable - i.e., give it a type, and a place in the namespace. Once a variable is declared, references to it will be consistent within its scope, and it cannot be re-assigned. (Mostly. There's some trickiness with member variable and local variables sharing a name, but you don't need to worry about that.)
Note that this doesn't assign a value. Primitive data types (int, boolean, double, etc), will have a default value (0 or false), which references will default to null.
<identifier> = <expression>;
computes the value of an expression, and updates an identifier to hold that value. You can combine these into:
<type> <identifier> = <expression>;
Which will declare a variable and immediately assign it a value.
while(<condition>) { <expressions> }
executes the expressions again and again until the condition becomes false. It only repeats the expressions between the curly braces, though.
In your code, nothing between those braces (i.e., "in the body of the while loop") actually updates those values. You only call the assignment statement outside of the while loop, so nothing ever changes.

How should I format my return statement so I don't double the answer?

private String twoDigits(int value) {
String result = "";
{
if ((mMinute >= 0) && (mMinute <= 9) && (mSecond >= 0) && (mSecond <= 9)) {
tempmin = ("0" + mMinute );
tempsec = ("0" + mSecond );
} else
tempmin = (mMinute + "");
tempsec = (mSecond + " ");
return tempin+tempsec;
This just doubles the output that I'm looking for and I was wondering, whether or not the issue was with the return statement or the actual method.
I need to call back to this method, twoDigits(mMinute)+":"+twoDigits(mSecond) to get the code to display the time, but instead of being able to display 10:09:08 I keep displaying 10:0908:0908
I was wondering how I should fix my code.
Since there are a lot of tiny mistakes in your code, I'll suggest a slightly different approach. Not sure if this method works, in what I assume is Java, but give it a shot:
private String twoDigits(int value)
{
return value <= 9 ? "0" + value : value;
}
This is actually an if/else abbreviation. Return the following: If value <= 9 then add a zero before the value, else the value.
If there's a risk of negative values being received, you could add this:
return (value >= 0 && value <= 9) ? "0" + value : value;
First, there's Paul's comment about the {} after else to encompass both rows. Then, you are not actually using the value received by the function but rather some global variables (mMinute and mSecond). You create but never use result. Furthermore, your if statement says that if both mMinute AND mSecond are between 0 and 9 then both should be fixed. Since you should use value you only have to check that variable's range and edit it accordingly. On the row tempsec = (mSecond + " "); you add a space.. mistake? Finally, you misspelled tempmin on the return row.
Good luck.
Note that your method has a value parameter. You should use this rather than directly access the fields in your class. Perhaps it might help for you to think about the purpose of the twoDigits() method. It seems to me that it is supposed to take an int value and pad it with a leading zero if the input is only a single digit. Note that my description in the previous sentence does not refer to the member variables that represent minutes and seconds; it only refers to the input value.

Object values and local values in arithmetic

So I was trying to perform a simple arithmetic on values within and object 'currentUser' in my one 'pricingAction' class.
The code should add the two volume values(doubles) and set the value of the variable to the sum of the two. In this example the volume_2, and volume_4 variable should be set to the sum of the two.
method 1:
if(filled4 == true){
if(currentUser.getUtility_2().equalsIgnoreCase(currentUser.getUtility_4())){
currentUser.setVolume_2(currentUser.getVolume_2() + currentUser.getVolume_4());
currentUser.setVolume_4(currentUser.getVolume_2() + currentUser.getVolume_4());
}
}
method 2:
if(filled3 == true){
if(currentUser.getUtility_2().equalsIgnoreCase(currentUser.getUtility_3())){
holder = 0;
holder = currentUser.getVolume_2() + currentUser.getVolume_3();
currentUser.setVolume_2(holder);
currentUser.setVolume_3(holder);
}
}
Method 2 returns the value expected and Method 1 appears to be tossing in a duplicate of the value it is setting to.
My question is why does Method 1 do this? I can only assume it is just tacking on the extra sum to the current value but the setter method is a generic this.x = x;
Let's simplify the code a little so it's easier to read:
foo.setX(foo.getX() + foo.getY());
foo.setY(foo.getX() + foo.getY());
Now suppose we start with foo.X = 10, foo.Y = 20.
The first statement will initially compute foo.X + foo.Y - which is 10+20, or 30.
It then sets that (30) as a new value for foo.X.
The second statement will initially compute foo.X + foo.Y, which is now 30+20, or 50. Note that this is using the new value of foo.X. It then sets 50 as a new value for foo.Y.
If you want to set the same value for both properties, you should compute that value once, to avoid the change to the value of the first property from affecting the computation. However, it's clearer to declare the local variable for that value as locally as you can:
double result = foo.getX() + foo.getY();
foo.setX(result);
foo.setY(result);
That's not only correct, but it's also easier to understand and more efficient. Bonus!
Because you have set the value of volume2 before using its new value to set volume4.
currentUser.setVolume_2(currentUser.getVolume_2() + currentUser.getVolume_4());
// volume2 now set with new value
// which you are about to use below
currentUser.setVolume_4(currentUser.getVolume_2() + currentUser.getVolume_4());
Your code is performing two additions (and I suspect you wanted one) -
if(currentUser.getUtility_2().equalsIgnoreCase(currentUser.getUtility_4())){
// Changes volume 2
currentUser.setVolume_2(currentUser.getVolume_2() + currentUser.getVolume_4());
currentUser.setVolume_4(currentUser.getVolume_2() + currentUser.getVolume_4());
}
Should probably be
if(currentUser.getUtility_2().equalsIgnoreCase(currentUser.getUtility_4())){
int newVolume = currentUser.getVolume_2() + currentUser.getVolume_4();
currentUser.setVolume_2(newVolume);
currentUser.setVolume_4(newVolume);
}

Reading value from field variable

I am developing desktop app in Java 7. I have here a situation. At the method below
private synchronized void decryptMessage
(CopyOnWriteArrayList<Integer> possibleKeys, ArrayList<Integer> cipherDigits)
{
// apply opposite shift algorithm:
ArrayList<Integer> textDigits = shiftCipher(possibleKeys, cipherDigits);
// count CHI squared statistics:
double chi = countCHIstatistics(textDigits);
if(chi < edgeCHI) // if the value of IOC is greater or equal than that
{
System.err.println(chi + " " + possibleKeys + " +");
key = possibleKeys; // store most suitable key
edgeCHI = chi;
}
}
I count the value called 'chi' and based on that if 'chi' is less than 'edgeCHI' value I save the key at instance variable. That method is invoked by some threads, so I enforce synchronization.
When all the threads complete the program continues to execute by passing control to a method which controls the sequence of operations. Then this line has been executed at that method:
System.err.println(edgeCHI+" "+key+" -");
It prints correct value of 'chi', as has been printed the last value of 'chi' at decryptMessage method, but the value of key is different. The 'decryptMessage' method has been invoked by threads which generate key values.
I store the key value as global variable
private volatile CopyOnWriteArrayList<Integer> key = null; // stores the most suitable key for decryption.
Why do I have two different key values? The values itself are not important. The matter is that the value of key printed at the last call at 'decryptMessage' method (when chi < edgeCHI) must match the one printed at the method which controls the flow of operations.
This is how you create threads:
for(int y = 0; y < mostOccuringL.length; y++){// iterate through the five most frequent letters
for(int i = (y + 1); i < mostOccuringL.length; i++ ){//perform letter combinations
int [] combinations = new int[2];
combinations[0] = y;
combinations [1] = i;
new KeyMembers(""+y+":"+i ,combinations, keywords, intKeyIndex, cipherDigits).t.join();
}
}
Within run method you invoke decryptMesssage method in order to identify most feasible decryption key.
I have been trying to figure out what is the prob for two days, but I don't get it.
Suggestions?
Relying on syserr (or sysout) printing to determine an order of execution is dangerous - especially in multi-threaded environments. There is absolutely no guarantuee when the printing actually occurs or if the printed messages are in order. Maybe what you see as "last" printed message of one of the threads wasn't the "last" thread modifying the key field. You cannot say that by looking only at sterr output.
What you could do is use a synchronized setter for the key field, that increases an associated access counter whenever the field is modified and print the new value along with the modification count. This way you can avoid the problems of syserr printing and reliably determine what the last set value was. e.g. :
private long keyModCount = 0;
private synchronized long update(CopyOnWriteArrayList<Integer> possibilities, double dgeChi) {
this.keys = possibilites;
this.edgeChi = edgeChi; // how is edgeChi declared? Also volatile?
this.keyModCount++;
return this.keyModCount;
}
And inside decryptMessage:
if(chi < edgeCHI) // if the value of IOC is greater or equal than that
{
long sequence = update(possibleKeys, chi);
System.err.println("["+ sequence +"]"+ chi + " " + possibleKeys + " +");
}
To provide an answer we would need to see more of the (simplified if necessary) code that controls the thread execution.
Solution has been found. I just changed CopyOnWriteArrayList data type into ArrayList at the point where field variable gets correct key. It works as expected now.

Categories

Resources