I am currently writing a code that calculates PI and E to the nth term. I enter a number in TermsJTextField, choose PI or E radio button (only one button can be active at a time), press calculate, and it's supposed to display the answer in the appropriate. However, when I press calculate, the application goes in a hang, and none of the buttons are responsive, even the x button. And the answer is never displayed.
Here's the code. I've narrowed down to the part that gives me a headache:
private void CalculateJButtonActionPerformed(java.awt.event.ActionEvent evt) {
final double MAX_VALUE = 10000; //Max value
double Start, End; //Star and end time
BigDecimal result = new BigDecimal ("0"); // Constants for result
BigDecimal Error = new BigDecimal ("0"); // And Error
DecimalFormat integerFormatter = new DecimalFormat("#0.");
Start = System.currentTimeMillis();
int Terms;
int count = 1;
boolean PIchecked = PiJRadioButton.isSelected();
boolean Echecked = EJRadioButton.isSelected();
double PI = 0;
double E = 1;
try
{
Terms = Integer.parseInt(TermsJTextField.getText());
if ((Terms <= 2) || (Terms >= 10000)) // This checks for the number of terms
{
throw new NumberFormatException();
}
else
{
if (PIchecked) // If Pi butoon is selected, do the following calculation
{
for (int i =1 ; 1 <= (Terms);i++)
{
count++;
result = result.add(new BigDecimal (Math.pow((-1.0),count)/(2*i-1)));
}
EJRadioButton.setSelected(false);
result = result.multiply(new BigDecimal (4.0));
Error = new BigDecimal(Math.abs(PI-result.doubleValue())/PI * 100.0);
}
else if (Echecked) // This calculates nth term for E
{
result = new BigDecimal("0");
long factorial = 1L;
for (int i = 1; i < Terms ; i++)
{
factorial *= i;
result = result.add(new BigDecimal(1.0/factorial));
}
result = result.add(new BigDecimal(1L));
Error = new BigDecimal(Math.abs(E-result.doubleValue())/E * 100.0);
PiJRadioButton.setSelected(false);
}
End = System.currentTimeMillis(); //Time in ms to calculate the answer
//Output
DecimalFormat Number = new DecimalFormat("#####0.##");
if (PIchecked)
{
EJTextField.setText("");
PIJTextField.setText(String.valueOf(result));
ErrorJTextField.setText(String.valueOf(Error + "%"));
}
else
{
PIJTextField.setText("");
EJTextField.setText(String.valueOf(result));
ErrorJTextField.setText(String.valueOf(Error + "%"));
}
PrintJButton.setEnabled(true);
PrintJMenuItem.setEnabled(true);
TimeJTextField.setText(String.valueOf(End-Start));
}
}
catch(NumberFormatException exp)
{
Object ERROR_MESSAGE = null;
JOptionPane.showMessageDialog(null, "Don't be silly; Enter a vaule between 2 and 10000",
"Input Error", JOptionPane.ERROR_MESSAGE);
TermsJTextField.selectAll();
TermsJTextField.setText("");
TermsJTextField.requestFocus();
}
}
It seems that your termination condition for your for-loop will never complete, as seen below:
for (int i =1 ; 1 <= (Terms);i++)
Switching it to the following should fix it (changed 1 to i):
for (int i = 1; i <= Terms; i++)
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.
So I have a task to calculate Euler's number using multiple threads, using this formula: sum( ((3k)^2 + 1) / ((3k)!) ), for k = 0...infinity.
import java.math.BigDecimal;
import java.math.BigInteger;
import java.io.FileWriter;
import java.io.IOException;
import java.math.RoundingMode;
class ECalculator {
private BigDecimal sum;
private BigDecimal[] series;
private int length;
public ECalculator(int threadCount) {
this.length = threadCount;
this.sum = new BigDecimal(0);
this.series = new BigDecimal[threadCount];
for (int i = 0; i < this.length; i++) {
this.series[i] = BigDecimal.ZERO;
}
}
public synchronized void addToSum(BigDecimal element) {
this.sum = this.sum.add(element);
}
public void addToSeries(int id, BigDecimal element) {
if (id - 1 < length) {
this.series[id - 1] = this.series[id - 1].add(element);
}
}
public synchronized BigDecimal getSum() {
return this.sum;
}
public BigDecimal getSeriesSum() {
BigDecimal result = BigDecimal.ZERO;
for (int i = 0; i < this.length; i++) {
result = result.add(this.series[i]);
}
return result;
}
}
class ERunnable implements Runnable {
private final int id;
private final int threadCount;
private final int threadRemainder;
private final int elements;
private final boolean quietFlag;
private ECalculator eCalc;
public ERunnable(int threadCount, int threadRemainder, int id, int elements, boolean quietFlag, ECalculator eCalc) {
this.id = id;
this.threadCount = threadCount;
this.threadRemainder = threadRemainder;
this.elements = elements;
this.quietFlag = quietFlag;
this.eCalc = eCalc;
}
#Override
public void run() {
if (!quietFlag) {
System.out.println(String.format("Thread-%d started.", this.id));
}
long start = System.currentTimeMillis();
int k = this.threadRemainder;
int iteration = 0;
BigInteger currentFactorial = BigInteger.valueOf(intFactorial(3 * k));
while (iteration < this.elements) {
if (iteration != 0) {
for (int i = 3 * (k - threadCount) + 1; i <= 3 * k; i++) {
currentFactorial = currentFactorial.multiply(BigInteger.valueOf(i));
}
}
this.eCalc.addToSeries(this.id, new BigDecimal(Math.pow(3 * k, 2) + 1).divide(new BigDecimal(currentFactorial), 100, RoundingMode.HALF_UP));
iteration += 1;
k += this.threadCount;
}
long stop = System.currentTimeMillis();
if (!quietFlag) {
System.out.println(String.format("Thread-%d stopped.", this.id));
System.out.println(String.format("Thread %d execution time: %d milliseconds", this.id, stop - start));
}
}
public int intFactorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i;
}
return result;
}
}
public class TaskRunner {
public static final String DEFAULT_FILE_NAME = "result.txt";
public static void main(String[] args) throws InterruptedException {
int threadCount = 2;
int precision = 10000;
int elementsPerTask = precision / threadCount;
int remainingElements = precision % threadCount;
boolean quietFlag = false;
calculate(threadCount, elementsPerTask, remainingElements, quietFlag, DEFAULT_FILE_NAME);
}
public static void writeResult(String filename, String result) {
try {
FileWriter writer = new FileWriter(filename);
writer.write(result);
writer.close();
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
public static void calculate(int threadCount, int elementsPerTask, int remainingElements, boolean quietFlag, String outputFile) throws InterruptedException {
long start = System.currentTimeMillis();
Thread[] threads = new Thread[threadCount];
ECalculator eCalc = new ECalculator(threadCount);
for (int i = 0; i < threadCount; i++) {
if (i == 0) {
threads[i] = new Thread(new ERunnable(threadCount, i, i + 1, elementsPerTask + remainingElements, quietFlag, eCalc));
} else {
threads[i] = new Thread(new ERunnable(threadCount, i, i + 1, elementsPerTask, quietFlag, eCalc));
}
threads[i].start();
}
for (int i = 0; i < threadCount; i++) {
threads[i].join();
}
String result = eCalc.getSeriesSum().toString();
if (!quietFlag) {
System.out.println("E = " + result);
}
writeResult(outputFile, result);
long stop = System.currentTimeMillis();
System.out.println("Calculated in: " + (stop - start) + " milliseconds" );
}
}
I stripped out the prints, etc. in the code that have no effect. My problem is that the more threads I use the slower it gets. Currently the fastest run I have is for 1 thread. I am sure the factorial calculation is causing some issues. I tried using a thread pool but still got the same times.
How can I make it so that running it with more threads, up until some point, will speed up the calculation process?
How would one go about calculating this big factorials?
The precision parameter that is passed is the amount of elements in the sum that are used. Can I set the BigDecimal scale to be somehow dependent on that precision so I don't hard code it?
EDIT
I updated the code block to be in 1 file only and runnable without external libs.
EDIT 2
I found out that the factorial code messes up with the time. If I let the threads ramp up to some high precision without calculating factorials the time goes down with increasing threads. Yet I cannot implement the factorial calculating in any way while keeping the time decreasing.
EDIT 3
Adjusting code to address answers.
private static BigDecimal partialCalculator(int start, int threadCount, int id) {
BigDecimal nBD = BigDecimal.valueOf(start);
BigDecimal result = nBD.multiply(nBD).multiply(BigDecimal.valueOf(9)).add(BigDecimal.valueOf(1));
for (int i = start; i > 0; i -= threadCount) {
BigDecimal iBD = BigDecimal.valueOf(i);
BigDecimal iBD1 = BigDecimal.valueOf(i - 1);
BigDecimal iBD3 = BigDecimal.valueOf(3).multiply(iBD);
BigDecimal prevNumerator = iBD1.multiply(iBD1).multiply(BigDecimal.valueOf(9)).add(BigDecimal.valueOf(1));
// 3 * i * (3 * i - 1) * (3 * i - 2);
BigDecimal divisor = iBD3.multiply(iBD3.subtract(BigDecimal.valueOf(1))).multiply(iBD3.subtract(BigDecimal.valueOf(2)));
result = result.divide(divisor, 10000, RoundingMode.HALF_EVEN)
.add(prevNumerator);
}
return result;
}
public static void main(String[] args) {
int threadCount = 3;
int precision = 6;
ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
ArrayList<Future<BigDecimal> > futures = new ArrayList<Future<BigDecimal> >();
for (int i = 0; i < threadCount; i++) {
int start = precision - i;
System.out.println(start);
final int id = i + 1;
futures.add(executorService.submit(() -> partialCalculator(start, threadCount, id)));
}
BigDecimal result = BigDecimal.ZERO;
try {
for (int i = 0; i < threadCount; i++) {
result = result.add(futures.get(i).get());
}
} catch (Exception e) {
e.printStackTrace();
}
executorService.shutdown();
System.out.println(result);
}
Seems to be working properly for 1 thread but messes up the calculation for multiple.
After a review of the updated code, I've made the following observations:
First of all, the program runs for a fraction of a second. That means that this is a micro benchmark. Several key features in Java make micro benchmarks difficult to implement reliably. See How do I write a correct micro-benchmark in Java? For example, if the program doesn't run enough repetitions, the "just in time" compiler doesn't have time to kick in to compile it to native code, and you end up benchmarking the intepreter. It seems possible that in your case the JIT compiler takes longer to kick in when there are multiple threads,
As an example, to make your program do more work, I changed the BigDecimal precision from 100 to 10,000 and added a loop around the main method. The execution times were measured as follows:
1 thread:
Calculated in: 2803 milliseconds
Calculated in: 1116 milliseconds
Calculated in: 1040 milliseconds
Calculated in: 1066 milliseconds
Calculated in: 1036 milliseconds
2 threads:
Calculated in: 2354 milliseconds
Calculated in: 856 milliseconds
Calculated in: 624 milliseconds
Calculated in: 659 milliseconds
Calculated in: 664 milliseconds
4 threads:
Calculated in: 1961 milliseconds
Calculated in: 797 milliseconds
Calculated in: 623 milliseconds
Calculated in: 536 milliseconds
Calculated in: 497 milliseconds
The second observation is that there is a significant part of the workload that does not benefit from multiple threads: every thread is computing every factorial. This means the speed-up cannot be linear - as described by Amdahl's law.
So how can we get the result without computing factorials? One way is with Horner's method. As an example, consider the simpler series sum(1/k!) which also conveges to e but a little slower than yours.
Let's say you want to compute sum(1/k!) up to k = 100. With Horner's method you start from the end and extract common factors:
sum(1/k!, k=0..n) = 1/100! + 1/99! + 1/98! + ... + 1/1! + 1/0!
= ((... (((1/100 + 1)/99 + 1)/98 + ...)/2 + 1)/1 + 1
See how you start with 1, divide by 100 and add 1, divide by 99 and add 1, divide by 98 and add 1, and so on? That makes a very simple program:
private static BigDecimal serialHornerMethod() {
BigDecimal accumulator = BigDecimal.ONE;
for (int k = 10000; k > 0; k--) {
BigDecimal divisor = new BigDecimal(k);
accumulator = accumulator.divide(divisor, 10000, RoundingMode.HALF_EVEN)
.add(BigDecimal.ONE);
}
return accumulator;
}
Ok that's a serial method, how do you make it use parallel? Here's an example for two threads: First split the series into even and odd terms:
1/100! + 1/99! + 1/98! + 1/97! + ... + 1/1! + 1/0! =
(1/100! + 1/98! + ... + 1/0!) + (1/99! + 1/97! + ... + 1/1!)
Then apply Horner's method to both the even and odd terms:
1/100! + 1/98! + 1/96! + ... + 1/2! + 1/0! =
((((1/(100*99) + 1)/(98*97) + 1)/(96*95) + ...)/(2*1) + 1
and:
1/99! + 1/97! + 1/95! + ... + 1/3! + 1/1! =
((((1/(99*98) + 1)/(97*96) + 1)/(95*94) + ...)/(3*2) + 1
This is just as easy to implement as the serial method, and you get pretty close to linear speedup going from 1 to 2 threads:
private static BigDecimal partialHornerMethod(int start) {
BigDecimal accumulator = BigDecimal.ONE;
for (int i = start; i > 0; i -= 2) {
int f = i * (i + 1);
BigDecimal divisor = new BigDecimal(f);
accumulator = accumulator.divide(divisor, 10000, RoundingMode.HALF_EVEN)
.add(BigDecimal.ONE);
}
return accumulator;
}
// Usage:
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<BigDecimal> submit = executorService.submit(() -> partialHornerMethod(10000));
Future<BigDecimal> submit1 = executorService.submit(() -> partialHornerMethod(9999));
BigDecimal result = submit1.get().add(submit.get());
There is a lot of contention between the threads: they all compete to get a lock on the ECalculator object after every little bit of computation, because of this method:
public synchronized void addToSum(BigDecimal element) {
this.sum = this.sum.add(element);
}
In general having threads compete for frequent access to a common resource leads to bad performance, because you're asking for the operating system to intervene and tell the program which thread can continue. I haven't tested your code to confirm that this is the issue because it's not self-contained.
To fix this, have the threads accumulate their results separately, and merge results after the threads have finished. That is, create a sum variable in ERunnable, and then change the methods:
// ERunnable.run:
this.sum = this.sum.add(new BigDecimal(Math.pow(3 * k, 2) + 1).divide(new BigDecimal(factorial(3 * k)), 100, RoundingMode.HALF_UP));
// TaskRunner.calculate:
for (int i = 0; i < threadCount; i++) {
threads[i].join();
eCalc.addToSum(/* recover the sum computed by thread */);
}
By the way would be easier if you used the higher level java.util.concurrent API instead of creating thread objects yourself. You could wrap the computation in a Callable which can return a result.
Q2 How would one go about calculating this big factorials?
Usually you don't. Instead, you reformulate the problem so that it does not involve the direct computation of factorials. One technique is Horner's method.
Q3 The precision parameter that is passed is the amount of elements in the sum that are used. Can I set the BigDecimal scale to be somehow dependent on that precision so I don't hard code it?
Sure why not. You can work out the error bound from the number of elements (it's proportional to the last term in the series) and set the BigDecimal scale to that.
In an interview I had, I was asked to write a program that prints to the screen the numbers 1,2,3,4,5....until 99999999999999.....?(the last number to print is the digit 9 million times)
You are not allowed to use Big-Integer or any other similar object.
The hint I got is to use modulo and work with strings, I tried to think about it but haven't figured it out.
Thanks in advance
You need an array to store the number, and perform operations on the array.
Here's an example
public class BigNumberTest2 {
public static void main(String[] args) {
/*Array with the digits of the number. 0th index stores the most significant digit*/
//int[] num = new int[1000000];
//Can have a million digits, length is 1 + needed to avoid overflow
int[] num = {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int base = 10;
int step = 1;
String endNum = "100000000000000000000000000000000000000000000000000020";//Can have a million digits
while(true) {
//Increment by step
for(int carry = step, i = num.length - 1; carry != 0 && i >= 0; i--) {
int newDigit = num[i] + carry;
num[i] = newDigit % base;
carry = newDigit / base;
}
//Find the position of most significant digit
int mostSignificantDigitIndex = 0;
while(num[mostSignificantDigitIndex] == 0) {/*No need to check if firstNonZero < num.length, as start num >=0 */
mostSignificantDigitIndex++;
}
StringBuilder strNum = new StringBuilder();
//Concatenate to get actual string
for(int i = mostSignificantDigitIndex; i < num.length; i++) {
strNum.append(num[i]);
}
System.out.println(strNum);
//Check if number current number is greater or equal to endNum
if(strNum.length() > endNum.length() || (strNum.length() == endNum.length() && strNum.toString().compareTo(endNum) >= 0)) {
break;
}
}
}
}
Output
1000000000000000000000000000000000000000000000000000001
1000000000000000000000000000000000000000000000000000002
1000000000000000000000000000000000000000000000000000003
1000000000000000000000000000000000000000000000000000004
1000000000000000000000000000000000000000000000000000005
1000000000000000000000000000000000000000000000000000006
1000000000000000000000000000000000000000000000000000007
1000000000000000000000000000000000000000000000000000008
1000000000000000000000000000000000000000000000000000009
1000000000000000000000000000000000000000000000000000010
1000000000000000000000000000000000000000000000000000011
1000000000000000000000000000000000000000000000000000012
1000000000000000000000000000000000000000000000000000013
1000000000000000000000000000000000000000000000000000014
1000000000000000000000000000000000000000000000000000015
1000000000000000000000000000000000000000000000000000016
1000000000000000000000000000000000000000000000000000017
1000000000000000000000000000000000000000000000000000018
1000000000000000000000000000000000000000000000000000019
1000000000000000000000000000000000000000000000000000020
Something like this:
This is a PHP, but you could transform it to java easy...
Recursion with increasing number through string.
function nextNum($num="", $step=1, $end="999999999999999999") {
$string = "";
$saving = 0;
for($i=strlen($num)-1; $i>=0; $i--) {
$calc = intval(intval($num[$i]) + $saving);
if ($i==(strlen($num)-1)) $calc = $calc + $step;
if (strlen($calc)==2) {
$calc = $calc."";
$saving = intval($calc[0]);
$calc = intval($calc[1]);
}
else {
$calc = intval($calc);
$saving = 0;
}
$string = $calc . $string;
}
if ($saving!=0) $string = $saving.$string;
echo $string." ";
if ($end == $string || strlen($end)<strlen($string)) { return; }
else return nextNum($string, $step, $end);
}
nextNum("0", 1, "999999999999999999");
I didn't test it... but it should work..
Java android is complain about how to make parse Integer from String array. My string array has almost 300 numbers. When I make the same code but parse it as float, the code works fine I don't want the decimal values. I just need the number itself. It is throwing java.lang.NumberFormatException: Invalid int: "97.601006". Would you mind to tell me what should I do. I also have one more question. I want to have the position/index of the peak value (Not the value itself) from my algorithm findPeaks. When I do peaks.get(i) the system is also crashing and says IndexOutOfBoundsException: Invalid index 24, size is 1
Thanks in advance.
String Adata = String.valueOf(stringBuilder);
String dataArray[];
dataArray = Adata.split("\\s+");
Log.i("TAG", "Size of dataArray: " + dataArray.length);
List String_TO_List = new ArrayList<Integer>();
int lastLength = dataArray.length - 1;
for (int i = 0; i < lastLength; i++) {
//the console pointed at this line with number format exception
int dataOfArray = Integer.parseInt(dataArray[i]);
if (dataOfArray > 170) {
String_TO_List.add(dataOfArray);
}
}
Log.i("TAG", "Size of list: " + String_TO_List.size());
List<Integer> List_Of_Peaks = findPeaks(String_TO_List);
Log.i(TAG, "Peaks" + List_Of_Peaks);
Peaks_num.setText(String.valueOf(List_Of_Peaks));
//my algorithm to find the peaks.
ArrayList<Float> peaks = new ArrayList<Float>();
float x1_n_ref = 0;
int alpha = 0; //0=down, 1=up.
int size = points.size();
for (int i = 0; i < size; i+=4) {
float IndexValues = points.get(i);
float delta = x1_n_ref - IndexValues;
if ( delta < 0) {
x1_n_ref = IndexValues;
alpha = 1;
} else if (alpha == 1 && delta > 0) {
peaks.add(x1_n_ref);
// here the system complain with Index exception. I want to know the poition or the index of the peak value so I can pass it to setText or Toast message.
peaks.get(i);
Log.i("TAG", "peak added: " + x1_n_ref);
alpha = 0;
} else if (alpha == 0 && delta > 0) {
x1_n_ref = IndexValues ;
}
//}
}
return peaks;
}
You can use Math.round(). It rounds a floating value to an integer. To round your value you have to parse it from String to double at first.
Replace your line
int dataOfArray = Integer.parseInt(dataArray[i]);
with
int dataOfArray = Math.round(Double.parseDouble(dataArray[i]));
Your example with "97.601006" will result in 98.
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.