Does anyone know how I can loop through this calculation 7 times?
public static double[] getNumSeedsPerType(String[] treeTypes, int[] numTreesPerType, final double FIR_DIE) {
double numSeeds = 0;
double[] numSeedsPerType = new double[numTreesPerType.length];
for (int i = 0; i < treeTypes.length; i++) {
if (treeTypes[i].equalsIgnoreCase("fir")) {
// This part of the calculation
numSeeds = numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);
numSeedsPerType[i] = numSeeds + numTreesPerType[i];
}
}
return numSeedsPerType;
}
If my understanding of your code is correct you can do the following:
Use a for loop to do the calculation 7 times.
Inside the loop change this code:
numSeeds = numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);
to this (so you can keep the results of every calculation):
numSeeds += numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);
Related
So I have created this program to randomly place objects in a room with a number of constraints. One such constraint is that every object has to be at least dis distance away from every other object already placed in the room. My entire code works well, however I often have to problem that the code stays stuck in the while loop. Here is that part of the code:
// distance vector to check whether the distance is kept
double[] dis2 = new double[k+1];
// distance vector to check whether the distance to the input/output is kept
double[] dis4 = new double[2];
dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
// Check the distance constraints
int l = 0;
while (l<k+1) {
dis2[l] = Math.abs(NewObjectX - PlacedX[l]) + Math.abs(NewObjectY - PlacedY[l]);
if (dis2[l]<dis || dis3>2.5*dis || dis4[0]<dis || dis4[1]<dis) {
NewObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
NewObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
dis3 = Math.abs(NewObjectX - PlacedX[k]) + Math.abs(NewObjectY - PlacedY[k]);
dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
l=0;
} else {
l++;
}
}
What happens: I randomly place a machine in the room and then I check the distance constraints with every already placed object in the while loop:
In the while loop, I check the distance constraint with the first, then second and so on objects that have already been placed.
If the distance constraints are not met, then a new randomly selected spot is selected and I restart the while loop l=0
I am not sure why my code sometimes stays stuck in that loop and most of the time works perfectly.
Could someone help me? Did I make an error?
Thank you so much :)
Sam
EDIT:
Here is a copy of the simplified code with only 1 constraint instead of 4 in the while loop:
public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
int[] WStoPlace = new int[WSNr-2];
for (int i=1; i<WSNr-1; i++) {
WStoPlace[i-1] = (i);
}
double[][] placed = new double[WSNr-2][3];
double ObjectX;
double ObjectY;
// now place the first object
ObjectX = dim[1]/2;
ObjectY = dim[3]/2;
placed[0][0] = WStoPlace[0];
placed[0][1] = ObjectX ;
placed[0][2] = ObjectY;
for (int i=1; i<WSNr-2; i++) {
//place the ith object
ObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
ObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
int l=0;
while (l<i) {
double dis2 = Math.abs(ObjectX - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
if (dis2<dis) {
ObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
ObjectX = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
l=0;
} else {
l++;
}
}
// Add the newly placed object
placed[i][0] = WStoPlace[i];
placed[i][1] = ObjectX;
placed[i][2] = ObjectY;
}
return placed;
}
This code is then called by my main program in a for-loop:
public static void main(String[] args) {
// define all the variables ...
int popFlow = 5;
double[] dim = new double [4];
dim[0] = 3; // length of WS (x)
dim[2] = 3; // width of WS (y)
dim[1] = 100; // length of facility (x)
dim[3] = 40;
double dis = 8;
int WSNr = 22;
double[] ioPlace = new double[4];
ioPlace[0] = 0; // int xi = 0;
ioPlace[1] = 5; // int yi = 2;
ioPlace[2] = 100; // int xo = 50;
ioPlace[3] = 35;
double[][] TotalPop = new double[popFlow][2*WSNr];
// Flow-related placed Workstations
for (int i=0; i<popFlow; i++) {
double [][] Pos = initialPop(dim, dis, WSNr, ioPlace);
for (int j=0; j<WSNr-2; j++) {
int Value = (int) Pos[j][0];
TotalPop[i][Value] = Pos[j][1];
TotalPop[i][Value+WSNr] = Pos[j][2];
}
}
}
As mentioned in the question's comments, you need to limit the loop. As a quick solution, you can have a counter that limits the while loop functionality and reset the entire logic which its probability to NOT go into same situation again is high. But that really should be handled better and check in which case exactly the loop would not end.
If the reason found and could be handled by the breaking conditions then it would be better as it would be more definite solution. Nevertheless, limiting the iteration for emergency is almost a must have. Here is simple sample on your code that would do something similar
public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
boolean reset = false;
double[][] placed = null;
while (!reset) {
int[] WStoPlace = new int[WSNr - 2];
for (int i = 1; i < WSNr - 1; i++) {
WStoPlace[i - 1] = (i);
}
placed = new double[WSNr - 2][3];
double ObjectX;
double ObjectY;
// now place the first object
ObjectX = dim[1] / 2;
ObjectY = dim[3] / 2;
placed[0][0] = WStoPlace[0];
placed[0][1] = ObjectX;
placed[0][2] = ObjectY;
for (int i = 1; i < WSNr - 2; i++) {
//place the ith object
ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
ObjectY = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;
// Problem is the while, not the for so we define the limit here
int limit = 100;
int counter = 0;
// Make sure it's false as it might be changed in some iteration before!
// I promised, check the comments below !
reset = false;
int l = 0;
while (l < i) {
double dis2 = Math.abs(ObjectX - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
if (dis2 < dis) {
ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
ObjectX = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;
l = 0;
} else {
l++;
}
if (counter >= limit) { // Now that's enough !
reset = true;
break;
}
counter++;
}
if (reset) { // I said it's enough, I want full reset so ...
reset = false; // going to break to the while-loop that checking this, and we want to enter again !
break;
} else {
// Not sure at this point this will be the last execution
// So just make it true, so we do not enter the entire logic again
// after finally settling to our result !!!!
// If it's not the last execution which means we are entering another for-loop iteration then
// we will reset this to false, i promise !
reset = true;
// Add the newly placed object
placed[i][0] = WStoPlace[i];
placed[i][1] = ObjectX;
placed[i][2] = ObjectY;
}
}
}
return placed;
}
You need a breakout. Add a counter or timer or check off coords as you try them until they are all checked. The way it is now there is no way to end the loop if your conditions in the "if" statement are always meet, it will just keep setting 'l' to 0 and your while loop just keeps looping.
Trying a method to find the power of a number using a for loop and without using Math.pow. For this result I just got 2.0 as it doesn't seem to go back round through the loop. Help please.
public void test() {
{
double t = 1;
double b = 2; // base number
double exponent = 2;
for (int i = 1; i<=exponent; i++);
t = t*b;
System.out.println(t);
Try this.
double t = 1;
double b = 2; // base number
double exponent = 2;
for (int i = 1; i<=exponent; i++) t = t*b;
System.out.println(t);
It's because the first iteration around you are setting T equal to B. You aren't multiplying by the exponent just yet. So it needs to iterate 1 further time then you are expecting. just decrease the I value in your for loop. EG
for(int i = 1; i <= exponent; i++)
t=t*b;
Hope this helps!
I am trying to simulate the math puzzle I found on http://blog.xkcd.com/2010/02/09/math-puzzle/. However, the java random class is returning weird results. In the code below, the result is what is expected. The output is somewhere around .612 for the first line and between .49 and .51 for the second.
int trials = 10000000;
int success = 0;
int returnstrue = 0;
for (int i = 0; i < trials; i++) {
Random r = new Random();
//double one = r.nextDouble()*10000;
//double two = r.nextDouble()*10000;
double one = 1;
double two = Math.PI;
double check = r.nextDouble();
boolean a = r.nextBoolean();
if(a)
{
returnstrue++;
}
if(a){
if((check>p(one)) && two > one)
{
success++;
}
if((check<p(one))&& two<one)
{
success++;
}
}
else{
if((check>p(two)) && two < one)
{
success++;
}
if((check<p(two))&& two>one)
{
success++;
}
}
}
System.out.println(success/(double)trials);
System.out.println(returnstrue/(double)trials);
However, when I switch the lines of
double check = r.nextDouble();
boolean a = r.nextBoolean();
to
boolean a = r.nextBoolean();
double check = r.nextDouble();
the output is around .476 for the first number and .710 for the second. This implies that the nextBoolean() method is returning true 70% of the time in the later configuration. Am I doing something wrong or is this just a bug?
Move the instantiation of r to outside the for loop, as in:
Random r = new Random();
for (int i = 0; i < trials; i++) {
:
}
What you are doing now is creating a new one every time the loop iterates and, since the seed is based on the time (milliseconds), you're likely to get quite a few with the same seed.
That's almost certainly what's skewing your results.
So, yes, it is a bug, just in your code rather than in Java. That tends to be the case in about 99.9999% of the times when people ask that question since Java itself is continuously being tested by millions around the world and that snippet of yours has been tested by, well, just you :-)
It actually is problem to find lucky number - those numbers whose sum of digits and sum of square of digits are prime. I have implemented Sieve of Eratosthenes. Now to optimize it further I commented my getDigitSum method, that I suppose was heavy and replaced with two hard-coded value , but it is still taking minutes to solve one test case. Here is a reference to actual problem asked
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Set;
import java.util.TreeSet;
public class Solution {
private static int[] getDigitSum(long num) {
long sum = 0;
long squareSum = 0;
for (long tempNum = num; tempNum > 0; tempNum = tempNum / 10) {
if (tempNum < 0) {
sum = sum + tempNum;
squareSum = squareSum + (tempNum * tempNum);
} else {
long temp = tempNum % 10;
sum = sum + temp;
squareSum = squareSum + (temp * temp);
}
}
int[] twosums = new int[2];
twosums[0] = Integer.parseInt(sum+"");
twosums[1] = Integer.parseInt(squareSum+"");
// System.out.println("sum Of digits: " + twoDoubles[0]);
// System.out.println("squareSum Of digits: " + twoDoubles[1]);
return twosums;
}
public static Set<Integer> getPrimeSet(int maxValue) {
boolean[] primeArray = new boolean[maxValue + 1];
for (int i = 2; i < primeArray.length; i++) {
primeArray[i] = true;
}
Set<Integer> primeSet = new TreeSet<Integer>();
for (int i = 2; i < maxValue; i++) {
if (primeArray[i]) {
primeSet.add(i);
markMutiplesAsComposite(primeArray, i);
}
}
return primeSet;
}
public static void markMutiplesAsComposite(boolean[] primeArray, int value) {
for (int i = 2; i*value < primeArray.length; i++) {
primeArray[i * value] = false;
}
}
public static void main(String args[]) throws NumberFormatException,
IOException {
// getDigitSum(80001001000l);
//System.out.println(getPrimeSet(1600));
Set set = getPrimeSet(1600);
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int totalCases = Integer.parseInt(br.readLine());
for (int cases = 0; cases < totalCases; cases++) {
String[] str = br.readLine().split(" ");
long startRange = Long.parseLong(str[0]);
long endRange = Long.parseLong(str[1]);
int luckyCount = 0;
for (long num = startRange; num <= endRange; num++) {
int[] longArray = getDigitSum(num); \\this method was commented for testing purpose and was replaced with any two hardcoded values
if(set.contains(longArray[0]) && set.contains(longArray[1])){
luckyCount++;
}
}
System.out.println(luckyCount);
}
}
}
what I should use to cache the result so that it takes lesser amount of time to search, currently it takes huge no. of minutes to complete 10000 test cases with range 1 99999999999999(18 times 9 -the worst case) , even thought the search values have been hard-coded for testing purpose( 1600, 1501 ).
You need a different algorithm. Caching is not your problem.
If the range is large - and you can bet some will be - even a loop doing almost nothing would take a very long time. The end of the range is constrained to be no more than 1018, if I understand correctly. Suppose the start of the range is half that. Then you'd iterate over 5*1017 numbers. Say you have a 2.5 GHz CPU, so you have 2.5*109 clock cycles per second. If each iteration took one cycle, that'd be 2*108 CPU-seconds. A year has about 3.1*107 seconds, so the loop would take roughly six and a half years.
Attack the problem from the other side. The sum of the squares of the digits can be at most 18*92, that's 1458, a rather small number. The sum of the digits itself can be at most 18*9 = 162.
For the primes less than 162, find out all possible decompositions as the sum of at most 18 digits (ignoring 0). Discard those decompositions for which the sum of the squares is not prime. Not too many combinations are left. Then find out how many numbers within the specified range you can construct using each of the possible decompositions (filling with zeros if required).
There are few places in this implementation that can be improved. In order to to start attacking the issues i made few changes first to get an idea of the main problems:
made the total start cases be the value 1 and set the range to be a billion (1,000,000,000) to have a large amount of iterations. also I use the method "getDigitSum" but commented out the code that actually makes the sum of digits to see how the rest runs: following are the methods that were modified for an initial test run:
private static int[] getDigitSum(long num) {
long sum = 0;
long squareSum = 0;
// for (long tempNum = num; tempNum > 0; tempNum = tempNum / 10) {
// if (tempNum < 0) {
// sum = sum + tempNum;
// squareSum = squareSum + (tempNum * tempNum);
// } else {
// long temp = tempNum % 10;
// sum = sum + temp;
// squareSum = squareSum + (temp * temp);
//
// }
// }
int[] twosums = new int[2];
twosums[0] = Integer.parseInt(sum+"");
twosums[1] = Integer.parseInt(squareSum+"");
// System.out.println("sum Of digits: " + twoDoubles[0]);
// System.out.println("squareSum Of digits: " + twoDoubles[1]);
return twosums;
}
and
public static void main(String args[]) throws NumberFormatException,
IOException {
// getDigitSum(80001001000l);
//System.out.println(getPrimeSet(1600));
Set set = getPrimeSet(1600);
//BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int totalCases = 1;
for (int cases = 0; cases < totalCases; cases++) {
//String[] str = br.readLine().split(" ");
long startRange = Long.parseLong("1");
long endRange = Long.parseLong("1000000000");
int luckyCount = 0;
for (long num = startRange; num <= endRange; num++) {
int[] longArray = getDigitSum(num); //this method was commented for testing purpose and was replaced with any two hardcoded values
if(set.contains(longArray[0]) && set.contains(longArray[1])){
luckyCount++;
}
}
System.out.println(luckyCount);
}
}
Running the code takes 5 minutes 8 seconds.
now we can start optimizing it step by step. I will now mention the various points in the implementation that can be optimized.
1- in the method getDigitSum(long num)
int[] twosums = new int[2];
twosums[0] = Integer.parseInt(sum+"");
twosums[1] = Integer.parseInt(squareSum+"");
the above is not good. on every call to this method, two String objects are created , e.g. (sum+"") , before they are parsed into an int. considering the method is called billion times in my test, that produces two billion String object creation operations. since you know that the value is an int (according to the math in there and based on the links you provided), it would be enough to use casting:
twosums[0] = (int)sum;
twosums[1] = (int)squareSum;
2- In the "Main" method, you have the following
for (long num = startRange; num <= endRange; num++) {
int[] longArray = getDigitSum(num); \\this method was commented for testing purpose and was replaced with any two hardcoded values
if(set.contains(longArray[0]) && set.contains(longArray[1])){
luckyCount++;
}
}
here there are few issues:
a- set.contains(longArray[0]) will create an Integer object (with autoboxing) because contains method requires an object. this is a big waste and is not necessary. in our example, billion Integer objects will be created. Also, usage of set, whether it is a treeset or hash set is not the best for our case.
what you are trying to do is to get a set that contains the prime numbers in the range 1 .. 1600. this way, to check if a number in the range is prime, you check if it is contained in the set. This is not good as there are billions of calls to the set contains method. instead, your boolean array that you made when filling the set can be used: to find if the number 1500 is prime, simply access the index 1500 in the array. this is much faster solution. since its only 1600 elements (1600 is greater than max sum of sqaures of digits of your worst case), the wasted memory for the false locations is not an issue compared to the gain in speed.
b- int[] longArray = getDigitSum(num);
an int array is being allocated and returned. that will happen billion times. in our case, we can define it once outside the loop and send it to the method where it gets filled. on billion iterations, this saved 7 seconds, not a big change by itslef. but if the test cases are repeated 1000 times as you plan, that is 7000 second.
therefore, after modifying the code to implement all of the above, here is what you will have:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Set;
import java.util.TreeSet;
public class Solution {
private static void getDigitSum(long num,int[] arr) {
long sum = 0;
long squareSum = 0;
// for (long tempNum = num; tempNum > 0; tempNum = tempNum / 10) {
// if (tempNum < 0) {
// sum = sum + tempNum;
// squareSum = squareSum + (tempNum * tempNum);
// } else {
// long temp = tempNum % 10;
// sum = sum + temp;
// squareSum = squareSum + (temp * temp);
//
// }
// }
arr[0] = (int)sum;
arr[1] = (int)squareSum;
// System.out.println("sum Of digits: " + twoDoubles[0]);
// System.out.println("squareSum Of digits: " + twoDoubles[1]);
}
public static boolean[] getPrimeSet(int maxValue) {
boolean[] primeArray = new boolean[maxValue + 1];
for (int i = 2; i < primeArray.length; i++) {
primeArray[i] = true;
}
for (int i = 2; i < maxValue; i++) {
if (primeArray[i]) {
markMutiplesAsComposite(primeArray, i);
}
}
return primeArray;
}
public static void markMutiplesAsComposite(boolean[] primeArray, int value) {
for (int i = 2; i*value < primeArray.length; i++) {
primeArray[i * value] = false;
}
}
public static void main(String args[]) throws NumberFormatException,
IOException {
// getDigitSum(80001001000l);
//System.out.println(getPrimeSet(1600));
boolean[] primeArray = getPrimeSet(1600);
//BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int totalCases = 1;
for (int cases = 0; cases < totalCases; cases++) {
//String[] str = br.readLine().split(" ");
long startRange = Long.parseLong("1");
long endRange = Long.parseLong("1000000000");
int luckyCount = 0;
int[] longArray=new int[2];
for (long num = startRange; num <= endRange; num++) {
getDigitSum(num,longArray); //this method was commented for testing purpose and was replaced with any two hardcoded values
if(primeArray[longArray[0]] && primeArray[longArray[1]]){
luckyCount++;
}
}
System.out.println(luckyCount);
}
}
}
Running the code takes 4 seconds.
the billion iterations cost 4 seconds instead of 5 minutes 8 seconds, that is an improvement. the only issue left is the actual calculation of the sum of digits and sum of squares of digits. that code i commented out (as you can see in the code i posted). if you uncomment it, the runtime will take 6-7 minutes. and here, there is nothing to improve except if you find some mathematical way to have incremental calculation based on previous results.
I am trying to calculate the normal log likelihood which is given by:
L = l1+l2+l3+...+ln,
where
lk = log(1/(sqrt(2*PI)*sigma_k))-0.5*e_k*e_k
Sigmas are around 0.2, and e_k are normally distributed with mean 0 and unit variance, so most of them are between -2 and 2;
I tried the following java code (sigma_k mentioned above = sigmas.get(k)*Math.sqrt(dt)):
private double new1(List<Double> residuals, List<Double> sigmas, double dt) {
double a = 0;
for(int i=0; i<sigmas.size(); i++) {
a += Math.log(1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i)));
}
double b = 0;
for(int i=0; i<residuals.size(); i++) {
b += residuals.get(i)*residuals.get(i);
}
return a-0.5*b;
}
but the theoretical maximum is lower than the maximum I got by doing numerical optimisation, so I have some suspicions that my method is suboptimal.
Remark:
In some areas probability/statistics are calculated without taking the log, for instance in linguistic frequencies of combinations.
The following simplifies, becoming less stable, but afterwards one convert it back to a sum of logs or so.
double a = 0;
for(int i=0; i<sigmas.size(); i++) {
a += Math.log(1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i)));
}
log(x) + log(y) = log(x*y)
double a = 1.0;
for(int i=0; i<sigmas.size(); i++) {
a *= 1.0/(Math.sqrt(2*Math.PI*dt)*sigmas.get(i));
}
a = Math.log(a);
(1/x)*(1/y) = 1/(x*y)
double a = 1.0;
for(int i=0; i<sigmas.size(); i++) {
a *= Math.sqrt(2*Math.PI*dt)*sigmas.get(i);
}
a = Math.log(1.0/a);
sqrt(x)^n = (x^0.5)^n = x^(n/2)
static import Math.*;
double a = pow(2*PI*dt, sigmas.size() / 2.0);
for(int i=0; i<sigmas.size(); i++) {
a *= sigmas.get(i);
}
a = -log(a);
I'm not sure if it will greatly improve numerical stability, but your equations can be simplified using logarithm laws:
log(a*b) = log(a) + log(b)
log(1/a) = -log(a)
log(sqrt(a)) = log(a)/2
so you have:
lk = -log(2*pi)/2 - log(sigma_k) - 0.5*e_k*e_k
= -log(2*pi)/2 - log(dt)/2 - log(sigmas.get(k)) - 0.5*e_k*e_k
= -log(2*pi*dt)/2 - log(sigmas.get(k)) - 0.5*e_k*e_k
First is constant, so in the first loop you only need to do a -= log(sigmas.get(k)).
Also, it look suspicious, that first loop is to sigmas.size() and the second to residuals.size() while the equation suggests, that they should have the same length.