Order of operations for compound assignment operators in Java - java

I came across the following on a mock exam recently, and was a bit lost as to why the answer given is 25, 25 according to the order of operations, and what I might be missing from the specification that gives the details as to why.
public class Test {
public static void main(String[] args) {
int k = 1;
int[] a = {1};
k += (k = 4) * (k + 2);
a[0] += (a[0] = 4) * (a[0] + 2);
System.out.println(k + " , " + a[0]);
}
}
Just looking at line 6 above I substitute the appropriate values, and get the following:
k = k + (k = 4) * (k + 2);
I evaluate the parenthesis first, which indicates k has first been assigned to the value of 4, and subsequently is added to the number 2, giving the total of 6. This is how I interpret that:
k = k + 4 * 6;
Now this is where it gets confusing. According to the order of operations I get the following, which would be correct given the previous expression:
k = k + 24;
In my thinking at this point k should be 4 because that was the new assignment, but the answer is actually 25, and not 28. Apparently compound operators have some order of precedence I'm not understanding, or my substitution principles are not correct.

In this answer, I will only consider the k case, it is the same for the array.
int k = 1;
k += (k = 4) * (k + 2);
// k += (k = 4) * (k + 2)
// 1 += (k = 4) * (k + 2)
// 1 += 4 * (k + 2) with k = 4
// 1 += 4 * 6 with k = 4
// k = 25
The tricks here:
k += captures the value of k before doing the calculation. += is called a compound assignment operator. Quoting the relevant part of the JLS:
the value of the left-hand operand is saved and then the right-hand operand is evaluated.
k = 4 returns the assigned value, so 4.

Related

Explain the implementation of Euler's Totient Implementation

I have seen this code in a coding platform to efficiently calculate the euler's totient for different values.
I am not being able to understand this implementation. I really want to learn this. Could anyone please help me explain this?
for(int i = 1; i < Maxn; i++) { // phi[1....n] in n * log(n)
phi[i] += i;
for(int j = 2 * i; j < Maxn; j += i) {
phi[j] -= phi[i];
}
}
First, lets note that for prime values p, phi(p) = p - 1. This should be fairly intuitive, because all numbers less than a prime must be coprime to said prime. So then we start into our outer for loop:
for(int i = 1; i < Maxn; i++) { // phi[1....n] in n * log(n)
phi[i] += i;
Here we add the value of i to phi(i). For the prime case, this means we need phi(i) to equal -1 beforehand, and all other phi(i) must be adjusted further to account for the number of coprime integers. Focusing on the prime case, lets convince ourselves that these do equal -1.
If we step through the loop, at case i=1, we'll end up iterating over all other elements in our inner loop, subtracting 1.
for(int j = 2 * i; j < Maxn; j += i) {
phi[j] -= phi[i];
}
For any other values to be subtracted j must equal the prime p. But that would require j = 2 * i + i * k to equal p, for some iteration k. That cannot be, because 2 * i + i * k == i * (2 + k) implying that p can be divided evenly by i, which it cannot (since its prime). Thus, all phi(p) = p - 1.
For non-prime i, we need to subtract out the number of coprime integers. We do this in the inner for loop. Reusing the formula from before, if i divides j, we get j / i = (2 + k). So every value less than i can be multiplied by (2 + k) to be less than j, yet have a common factor of (2 + k) with j (thus, not coprime).
However, if we subtracted out (i - 1) multiples containing (2 + k) factors, we'd count the same factors multiple times. Instead, we only count those which are coprime to i, or in other words phi(i). Thus, we are left with phi(x) = x - phi(factor_a) - phi(factor_b) ... to account for all the (2 + k_factor) multiples of coprimes less than said factor, which now share a factor of (2 + k_factor) with x.
Putting this into code gives us exactly what you have above:
for(int i = 1; i < Maxn; i++) { // phi[1....n] in n * log(n)
phi[i] += i;
for(int j = 2 * i; j < Maxn; j += i) {
phi[j] -= phi[i];
}
}
By the way, just out of interest, there's also an O(n) algorithm to achieve the same. We know Euler's product formula for the totient is
phi(n) = n * product(
(p - 1) / p)
where p is a distinct prime that divide n
For example,
phi(18) = 18 * (
(2-1)/2 * (3-1)/3)
= 18 * 2/6
= 18 * 1/3
= 6
Now consider a number m = n * p for some prime p.
phi(n) = n * product(
(p' - 1) / p')
where p' is a distinct prime that divide n
If p divides n, since p already appears in the calculation for phi(n), we do not need to add it to the product section, rather we just add it to the initial multiplier
phi(m) = phi(p * n) = p * n * product(
(p' - 1) / p')
= p * phi(n)
Otherwise, if p does not divide n, we need to use the new prime,
phi(m) = phi(p * n) = p * n * product(
(p' - 1) / p') * (p - 1) / p
= p * (p - 1) / p * n * product(
(p' - 1) / p')
= (p - 1) * phi(n)
Either way, we can calculate the totient of a number multiplied by a prime only from the prime and the number's own totient, which can be aggregated in O(n) by repeatedly multiplying the numbers we've generated so far by the next prime we find until we reach Maxn. We find the next prime by incrementing an index to the successor we haven't recorded a totient for (prime generation here is a benefit).

Magic square code loop

This is the code for a method which creates a magic square. n is the length of the square. It has to look like:
static int[][] magicSquare(int n) {
int[][] square=new int[n][n];
I don't understand this k=(k+1)%n; especially, why is it %n ?? Doesn´t that put k to 1 every loop again?
for (int i=0; i<n; i++){
in k=i;
for (int j=0; j<n; j++){
square[i][j]=k+1;
k=(k+1)%n;
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
The % in Java is used for modular division. Whenever the operator is applied the right-hand operand will be subtracted as many times as it can from the left-hand operand and what's left will be the output. You can easily check it by dividing the left-hand operand by the right-hand operand and take the leftover as an integer. In the case of a%b it will be like
a - (a/b)*b.
here are some examples:
10 % 4 = 2 // 2*4 = 8 + 2 = 10
10 % 5 = 0 // 2*5 = 10 + 0 = 10
0 % 4 = 0 // result here is 0 thus 0*4 = 0 + 0 = 0
// if you try to extract 4 from 0, you will not succeed and what's left will be returned (which was originally 0 and it's still 0)...
In your case:
k = (k + 1) % n;
is assuring that the value of k will never exceed 4, thus if it is dividable by 4 then it will be divided and the leftover will be written there. In the case when k is exactly 4 you will have the value of 0 written down into k but since you are always adding k + 1 it is writing the value of 1.
For beginners I do recommend to print the values you are interested in and observe how do the data migrate. Here I've added some printlns for you just to get the idea. Run the code and test it yourself. I do believe the things are going to be a bit cleaner.
public static void main(String[] args) {
int n = 4;
int[][] square = new int[n][n];
System.out.println("--------------");
for (int i = 0; i < n; i++) {
int k = i;
System.out.println("Filling magic cube line " + (i + 1) + ". The k variable will start from " + i + "."); // i initial value is 0 so we add 1 to it just to get the proper line number.
for (int j = 0; j < n; j++) {
System.out.println("Filling array index [" + i + "][" + j + "] = " + (k + 1)); // array indexes start from 0 aways and end at array.length - 1, so in case of n = 4, last index in array is 3.
square[i][j] = k + 1; // add 1 to k so the value will be normalized (no 0 entry and last entry should be equal to n).
k = (k + 1) % n; // reset k if it exceeds n value.
}
System.out.println("--------------");
}
Arrays.stream(square).forEach(innerArray -> {
Arrays.stream(innerArray).forEach(System.out::print);
System.out.println();
});
}
You could always play around and refactor the code as follows:
public static void main(String[] args) {
int n = 4;
int[][] square = new int[n][n];
System.out.println("--------------");
for (int i = 1; i <= n; i++) {
int k = i;
System.out.println("Filling magic cube line " + i + ". The k variable will start from " + i + ".");
for (int j = 0; j < n; j++) {
System.out.println("Filling array index [" + (i - 1) + "][" + (j - 1) + "] = " + k); // array indexes start from 0 aways and end at array.length - 1, so in case of n = 4, last index in array is 3. Subtract both i and j with 1 to get the proper array indexes.
square[i - 1][j - 1] = k;
k = (k + 1) % n; // reset k if it exceeds n value.
}
System.out.println("--------------");
}
Arrays.stream(square).forEach(innerArray -> {
Arrays.stream(innerArray).forEach(System.out::print);
System.out.println();
});
}
Remember that the array's indexing starts from 0 and ends at length - 1. In the case of 4, the first index is 0 and the last one is 3. Here is the diff of two implementations, try to see how does the indexes and values depends both on the control variables i and j.
https://www.diffchecker.com/x5lIWi4A
In the first case i and j both start from 0 and are growing till they it's values are both less than n, and in the second example they start from 1 and are growing till they are equal to n. I hope it's getting clearer now. Cheers

Why does this code to generate 4 distinct random numbers throw an ArrayIndexOutOfBoundsException? [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 5 years ago.
I'm trying to generate 4 random numbers without duplicates, using a loop, but I get an ArrayIndexOutOfBoundsException. Can someone please explain why?
// SECRET ANSWER
int secret[] = new int[4];
for (int i = 0; i < secret.length; i++) {
secret[i] = (int) (Math.random() * 6 + 1);
if (secret[i] == secret[i + 1] || secret[i] == secret[i + 2] || secret[i] == secret[i + 3]) {
secret[i] = (int) (Math.random() * 6 + 1);
}
if (secret[i + 1] == secret[i + 2] || secret[i + 1] == secret[i + 3]) {
secret[i] = (int) (Math.random() * 6 + 1);
}
if (secret[i + 2] == secret[i + 3]) {
secret[i] = (int) (Math.random() * 6 + 1);
}
}
So, imagine situation when you are on the last element in the array.
You try to get I+1, I+2, I+3 elements which do not exist. You need to change limit to length - 3 or do something similar
you mentioned array size 4 and you are trying to increase it that's why u are getting that exception.you can store only fixed size of elements in the array. It doesn't grow its size at runtime. To overcome this problem, use collection framework.
In the second iteration of the for loop, i is 1. The first two conditions in your 'or' chain are false, so the third is evaluated, which causes secret[i + 3] to be accessed. i + 3 is 4, but secret only has indexes 0 to 3. Your algorithm makes no sense.
This generates an array of 4 distinct, random numbers in the range [1..6]:
Random rand = new Random();
int[] secret = rand.ints(1, 7).distinct().limit(4).toArray();
Although, if you must use for loops, you should check all elements before the current index using a nested for loop, as this is all you need to check. You should also use a while loop to make sure you keep generating random numbers until you get one that hasn't been generated yet.
For example:
int[] secret = new int[4];
for (int i = 0; i < secret.length; i++) {
int n;
boolean distinct;
do {
distinct = true;
n = (int) (Math.random() * 6 + 1);
for (int j = 0; j < i; j++) {
if (secret[j] == n) {
distinct = false;
}
}
} while (!distinct);
secret[i] = n;
}

Recursive function to iterative function as binoms

I'm new with algorithms and wonder how this displayed function is supposed to be converted/transformed from recursive to iterative. What should I keep in mind when converting?
public int binom(int n, int k)
{
if (k == 0 || n == k) { return 1; }
return binom(n - 1, k - 1) + binom(n - 1, k);
}
Thanks in advance!
In fact, this problem is not so easy, if you just look at the recursive code and try to decrypt it.
However, it might be a helpful hint for you, that (n over k), i.e. the binomial coefficient can be written as
n! / (k! * (n - k)!)
where "!" denotes the factorial.
And it should be rather easy to compute the factorial in a Loop (i.e. iterative) for you.
If intermediate results are too big you can shorten before computation. You can shorten either term k! or the term (n-k)! (you would choose the bigger one). For example with n = 5 and k = 3 you have:
(1 * 2 * 3 * 4 * 5) / ((1 * 2 * 3) * (1 * 2)) = (4 * 5) / (1 * 2)
Spoiler-Alarm:
public static int binomial(int n, int k) {
int nMinusK = n - k;
if (n < nMinusK) {
//Switch n and nMinusK
int temp = n;
n = nMinusK;
nMinusK = temp;
}
int result = 1;
// n!/k!
for (int i = k + 1; i <= n; i++) {
result *= i;
}
//Division by (n-k)!
for (int j = 1; j <= nMinusK; j++) {
result = result / j;
}
return result;
}
You can use the multiplicative form of binomial coefficients, for example from Wikia, which can be easily implemented with faculties or loops.

while nested in for loop. How does the decrement operator work?

I couldn't figure out how the decrement operator (e--)
works in code below, so i wrote the other class below it
to get the same result. I want to know how the decrement operator
achieves that result in the Power class. - Newbie.
int result, e;
for(int i=0; i < 10; i++) {
result = 1;
e = i;
while(e > 0) {
result *= 2;
e--;
}
System.out.println("2 to the " + i +
" power is " + result);
}
Code written to achieve same result
int result = 1;
for(int i=0; i < 10; i++) {
if (i > 0) {
result*=2;
}
System.out.println("2 to the " + i +
" power is " + result);
}
So the first example is resetting result for each iteration of the main for loop, so it needs to recalculate from scratch each time, where as the second example is keeping the previous computed value. The if in the second example is not needed is it.
The decrement operator modifies the variable on which it's called. So e-- is effectively e = e - 1 (except the overall result of the expression is different, see below).
This code:
result = 1;
e = i;
while(e > 0) {
result *= 2;
e--;
}
starts with result = 1 and then loops for i iterations doubling the value in result. Equivalent code using for which you seem more comfortable with:
result = 1;
for (e = 0; e < i; e++) {
result *= 2;
}
There are two forms of the decrement (and increment) operator: Prefix and postfix, depending on whether the operator is before (prefix) or after (postfix) its operand. Either could be used in the code you were asking about, because the only difference is the result of the expression.
Prefix: Suppose we have x = 5. The expression --x has the value 4: First we decrement x, then we take its new value as the result of the expression.
Postfix: Suppose we had x = 5 (again). The expression x-- has the value 5, with x ending up containing 4: First we grab the current value of x as the result of the expression, then we decrement it (because the -- is after x).
int x, r;
x = 5;
r = --x; // Prefix
System.out.println("r = " + r + ", x = " + x); // "r = 4, x = 4"
x = 5;
r = x--; // Postfix
System.out.println("r = " + r + ", x = " + x); // "r = 5, x = 4"
i figure out that by placing a System.out.println(e) i could "see" the variable "e" behavior in order to make sense of the decrement.
class Power {
public static void main(String args[]) {
int e;
int result;
for(int i=0; i < 10; i++) {
result =1 ;
e = i;
while(e > 0) {
System.out.println(e); // not part of the original program
result *= 2 ;
e--;
System.out.println(e); // not part of the original program
}
//System.out.println("2 to the " + i +
//" power is " + result);
}
This is the output:
C:\Users\enrique\Desktop\Hello.java>java Power: 1, 0, 2, 1, 1, 0, 3
e = 1(iteration 1), 2^1, e (1) decremented to 0, e = 2 (iteration 2), 2^2, e(2) decremented to 1, e = 1 re-enter The while but is ignored as 2^1 is already registered, e (1) decremented to 0, e = 3 (iteration 3), 2^3…

Categories

Resources