Why doesn't the compiler allow this? - java

since I desperately search for a solution for 3 hours, but didn't find anything, I'm gonna try it here.
public static void Assemble(boolean isAnnuityLoan, double K, double P, int N) {
double loan = K;
int year = 1;
Output.PrintHeader();
if (isAnnuityLoan) {
double *rpy* = Calculation.AnnRatePerYear(K, P, N);
} else {
double *T* = Calculation.AmortRate(N, K);
}
for (int x = 0; x < N; x++) {
double I = Calculation.Interest(loan, P);
if (isAnnuityLoan) {
double T = Calculation.AnnAmortRate(**rpy**, loan, P);
} else {
double rpy = Calculation.RatePerYear(loan, P, **T**);
}
Output.PrintTableLine(year, loan, I, **T**, **rpy**);
loan = loan - **T**;
year++;
System.out.println("\n");
}
Thats the code. Oh cool looks like formatting doesnt work in the code segment. Anyway, problem is, compiler marks the italic variables (K and rpy) as not used, and the bold ones (double stars) as not found. Now this doesnt make any sense to me, because lets trace both paths.
isAnnuityLoan is false. itll calculate T, then enter the for loop and since isAnnuityLoan is still false, the else statement will trigger and rpy will be calculated.
is vice versa, rpy gets calculated first, the T in the loop, and therefore both variables should be available.
Buuuut theyre not. And I have no idea why. Now where is the issue with this?
You help is highly apprechiated and will help me not to riddle about this in my sleep.

"rpy" variable is defined inside an if scope, so you can't it outside.
To use variables outside if scope, take a look at the example below.
Note that warnings are different than errors. Compiler WILL compile your code even if it contains warnings like (variable not used) but NOT errors.
example :
//define var
int x;
if(test){
//initialize it here
x = 1;
} else {
//or here
x = 2;
}
//use it here
System.out.println(x);

Related

Why is x not initialized in this?

Why is x not initialized in the following ?
public class rough {
public static void main(String[] args) {
int x;
boolean found = false;
for (int i = 0; i < 10; i++) {
if (Math.random() < 0.5) {
found = true;
x = 10;
break;
}
}
if (!found)
x = -1;
System.out.println(x);//x isn't initialized here
}
}
On average, for half of the iterations, the if inside the for loop would be true, thus initializing x. For the other half, found stays false therefore the outer if would initialize. Therefore, I don't understand why the compiler is annoyed.
As the ultimate distillation (see successive simplifications below), consider
public static void main(String[] args) {
int x;
boolean found = false;
if (!found)
x = -1;
System.out.println(x);
}
which also gives the error that x isn't init.
previous simplifications
Even more surprisingly, changing
if (Math.random() < 0.5) to if(true) also has the same problem.
In fact, investigating further, replacing the original for loop by these
for (int i=0;i<1;i++)
x = 10;
for (; !found; ) {
x = 10;
break;
}
is equally worse. Only for(;;){... break;} & for(;true;){... break;} don't raise any init. errors.
The compiler can't easily detect all branches lead to x being initialized, but you can fix that (and the code) pretty easily by assigning -1 to x to begin with. Something like
public static void main(String[] args) {
int x = -1;
for (int i = 0; i < 10; i++) {
if (Math.random() < 0.5) {
x = 10;
break;
}
}
System.out.println(x);
}
And now you don't need found (so I removed it too).
(Writing this up as a separate answer since I think it'll benefit from being taken out of comments).
This is the language-lawyer's answer.
The language specification requires initialization of variables before they are used.
The rules include:
The variable must be given a value on all possible paths through the code. The specification refers to this as 'definite assignment'.
The compiler does not consider the values of expressions in this analysis. See Example 16.2 for this.
The second rule explains why even in cases that are 'obvious' to us, the compiler can't use that knowledge. Even if the compiler-writer cared to do a deeper analysis, adherence to the Java specification forbids it.
If the next question is 'but why?' then I'd have to guess, but the point of a standard is to get consistent behaviour. You don't want one compiler accepting as legal Java something that another compiler rejects.

How to recall a method n amount of times?

trying to recall a method here (so that it generates different results 100 times using a for loop)
Here is what I have in the main method:
for (int i = 0; i<99; i++) {
double scaleFitness = ScalesSolution.ScalesFitness(randomNumberFile);
System.out.print(scaleFitness + ", ");
}
and this is the method I'm trying to call 100 times (in the ScalesSolution class):
public static double ScalesFitness(ArrayList<Double> weights)
{
int n = scasol.length();
double lhs = 0.0, rhs = 0.0;
if (n > weights.size()) return(-1);
for(int i = 0; i < n; i++){
if(scasol.charAt(i) == '0'){
lhs += weights.get(i);
}
else if (scasol.charAt(i) == '1') {
rhs += weights.get(i);
}
}
return(Math.abs(lhs-rhs));
}
This however prints the same value 100 time over.
Your method "ScaleFitness" and the output of this method is dependent on two variables:
weights
scasol
It seems these variables stay the same for the whole run of the program. So it is not surprising that your output is the same.
If you want a different output for each run of your loop. You need to reset at least one of these variables to a new value.
Btw. methods in Java always start with a lowercase. Classes start with an uppercase.
public static double scalesFitness(ArrayList<Double> weights)
{
double randomElement = weights[((int) (Math.random() * weights.size()))];
This will enable you to retrieve a random element in the array, for manipulation later.

Creating different power methods

I had some code that calculates powers, by calling square, cube and hypercube methods. Currently the cube method calls the square method in the program, and then the hypercube method calls the cube method. I want to replace the calls to cube and hypercube with calls to the power method, but I'm completely stuck.
Here's the original code which worked.
public int square( int x ){
int i = ( x*x );
return i;
}
public int cube( int x ){
int i = (x * square(x) );
return i;
}
public int hypercube( int x ){
int i = (x * cube(x) );
return i;
}
public int power(int x, int n){
int k;
if (n==2){
k = square(x);
}
else if (n==3){
k = cube(x);
}
else if (n==4){
k = hypercube(x);
}
else if (n==1){
k = x;
}
else {
k = 1;
for (int i = 0; i < n; i++) {
k *= x;
}
}
return k;
}
Now like I said I want to replace the calls in the cube and hypercube methods with calls to the power method, then I still have calls to square, cube etc in the power method. So I want to remove calls to these methods entirely since I no longer need them. Its really bugging me.
This is what I have so far but its giving me StackOverFlowError.
public int square( int x, int n ){
int i = power( x, n );
return i;
}
public int cube( int x, int n ){
int i = power(x , n );
return i;
}
public int hypercube( int x, int n ){
int i = power(x , n );
return i;
}
public int power(int x, int n){
int k;
if (n==2){
k = square(x, n);
}
else if (n==3){
k = cube(x, n);
}
else if (n==4){
k = hypercube(x, n);
}
else if (n==1){
k = x;
}
else {
k = 1;
for (int j = 0; j < n; j++) {
k *= x;
}
}
return k;
}
First off, as you've recognized this is a very bad way of going about things. So anybody else reading this, apart from the usual call to avoid reinventing the wheel (unless it's for educational purposes) don't implement your exponentiation methods this way!
That being said, the reason you're getting a stack overflow (so appropriate) is that you have a circular definition. The simplest way to see this is trying to track down how power works by hand. Let's say I want to run power(3, 2). What happens? Well power(3, 2) recognizes this as an instance of n == 2 and so goes to the square method. However, the square method relies on the power method to get things done and then you repeat ad infinitum. Hence you get function calls piling up on your stack until you run out of space.
P.S. Incidentally, if you are looking at implementing integer exponentiation for personal edification, you might want to look into repeated squaring. It makes your code much faster (a logarithmic number of multiplication operations as opposed to a linear number).
It looks to me that there is an infinite cycle going on here.
If n=2, then power calls sqaure which in turn calls power and n doesn't change either.
You get StackOverFlowError usually when you deal with infinities.
power(x,n) must be independent of cube or square if you want to get rid of those.

Java: "Local variable may not have been initialized" not intelligent enough?

Consider the following method:
void a ()
{
int x;
boolean b = false;
if (Math.random() < 0.5)
{
x = 0;
b = true;
}
if (b)
x++;
}
On x++ I get the "Local variable may not have been initialized" error. Clearly x will never be used uninitialized. Is there any way to suppress the warning except by initializing x? Thanks.
No, there is no way Java can examine all possible code paths for a program to determine if a variable has been initialized or not, so it takes the safe route and warns you.
So no, you will have to initialize your variable to get rid of this.
There is one :
void a () {
if (Math.random() < 0.5) {
int x = 1;
}
}
The compiler isn't responsible for devising and testing the algorithm. You are.
But maybe you should propose a more practical use case. Your example doesn't really show what's your goal.
Why don't you simply use
void a ()
{
int x;
boolean b = false;
if (Math.random() < 0.5)
{
x = 0;
b = true;
x++;
}
if (b) {
//do something else which does not use x
}
}
In the code why do you want to use x outside the first if block, all the logic involving x can be implemented in the first if block only, i don't see a case where you would need to use the other if block to use x.
EDIT: or You can also use:
void a ()
{
int x;
boolean b = (Math.random() < 0.5);
if (b) {
x=1
//do something
}
}
You can and should be defining the value of x unconditionally if it will be used later in your code.
There are a few ways to do this:
On initialization
int x = 0;
Because this is outside the conditional (if), Java won't complain.
Add else clause to conditional
if (Math.random() < 0.5)
{
x = 0;
b = true;
} else
{
x = 1;
}
Because there is an else to this if, and both code paths initialize x, Java will also be happy with this.
Move your usage of the variable into the conditional block
Clearly the question has a minimally-reproducible example, not a full one, but if you only ever want to use the variable conditionally, then it belongs in the conditional block.
if (Math.random() < 0.5)
{
x = 0;
x++;
}
If you don't aren't conditionally using the variable, then you need to provide an integer value to use in case Math.random() >= 0.5, using one of the solutions above.

Function Values using Differential Evolution

How can I use differential evolution to find the maximum values of the function function f(x) = -x(x+1) from -500 to 500? I need this for a chess program I am making, I have begun researching on Differential Evolution and am still finding it quite difficult to understand, let alone use for a program. Can anyone please help me by introducing me to the algorithm in a simple way and possibly giving some example pseudo-code for such a program?
First, of all, sorry for the late reply.
I bet that you won't know the derivatives of the function that you'll be trying to max, that's why you want to use the Differential Evolution algorithm and not something like the Newton-Raphson method.
I found a great link that explains Differential Evolution in a straightforward manner: http://web.as.uky.edu/statistics/users/viele/sta705s06/diffev.pdf.
On the first page, there is a section with an explanation of the algorithm:
Let each generation of points consist of n points, with j terms in each.
Initialize an array with size j. Add a number j of distinct random x values from -500 to 500, the interval you are considering right now. Ideally, you would know around where the maximum value would be, and you would make it more probable for your x values to be there.
For each j, randomly select two points yj,1 and yj,2 uniformly from the set of points x
(m)
.
Construct a candidate point cj = x
(m)
j + α(yj,1 − yj,2). Basically the two y values involve
picking a random direction and distance, and the candidate is found by adding that random
direction and distance (scaled by α) to the current value.
Hmmm... This is a bit more complicated. Iterate through the array you made in the last step. For each x value, pick two random indexes (yj1 and yj2). Construct a candidate x value with cx = α(yj1 − yj2), where you choose your α. You can try experimenting with different values of alpha.
Check to see which one is larger, the candidate value or the x value at j. If the candidate value is larger, replace it for the x value at j.
Do this all until all of the values in the array are more or less similar.
Tahdah, any of the values of the array will be the maximum value. Just to reduce randomness (or maybe this is not important....), average them all together.
The more stringent you make the about method, the better approximations you will get, but the more time it will take.
For example, instead of Math.abs(a - b) <= alpha /10, I would do Math.abs(a - b) <= alpha /10000 to get a better approximation.
You will get a good approximation of the value that you want.
Happy coding!
Code I wrote for this response:
public class DifferentialEvolution {
public static final double alpha = 0.001;
public static double evaluate(double x) {
return -x*(x+1);
}
public static double max(int N) { // N is initial array size.
double[] xs = new double[N];
for(int j = 0; j < N; j++) {
xs[j] = Math.random()*1000.0 - 500.0; // Number from -500 to 500.
}
boolean done = false;
while(!done) {
for(int j = 0; j < N; j++) {
double yj1 = xs[(int)(Math.random()*N)]; // This might include xs[j], but that shouldn't be a problem.
double yj2 = xs[(int)(Math.random()*N)]; // It will only slow things down a bit.
double cj = xs[j] + alpha*(yj1-yj2);
if(evaluate(cj) > evaluate(xs[j])) {
xs[j] = cj;
}
}
double average = average(xs); // Edited
done = true;
for(int j = 0; j < N; j++) { // Edited
if(!about(xs[j], average)) { // Edited
done = false;
break;
}
}
}
return average(xs);
}
public static double average(double[] values) {
double sum = 0;
for(int i = 0; i < values.length; i++) {
sum += values[i];
}
return sum/values.length;
}
public static boolean about(double a, double b) {
if(Math.abs(a - b) <= alpha /10000) { // This should work.
return true;
}
return false;
}
public static void main(String[] args) {
long t = System.currentTimeMillis();
System.out.println(max(3));
System.out.println("Time (Milliseconds): " + (System.currentTimeMillis() - t));
}
}
If you have any questions after reading this, feel free to ask them in the comments. I'll do my best to help.

Categories