I've been trying to implement Euclid's algorithm in Java for 2 numbers or more.The problem with my code is that
a) It works fine for 2 numbers,but returns the correct value multiple times when more than 2 numbers are entered.My guess is that this is probably because of the return statements in my code.
b) I don't quite understand how it works.Though I coded it myself,I don't quite understand how the return statements are working.
import java.util.*;
public class GCDCalc {
static int big, small, remainder, gcd;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// Remove duplicates from the arraylist containing the user input.
ArrayList<Integer> listofnum = new ArrayList();
System.out.println("GCD Calculator");
System.out.println("Enter the number of values you want to calculate the GCD of: ");
int counter = sc.nextInt();
for (int i = 0; i < counter; i++) {
System.out.println("Enter #" + (i + 1) + ": ");
int val = sc.nextInt();
listofnum.add(val);
}
// Sorting algorithm.
// This removed the need of conditional statements(we don't have to
// check if the 1st number is greater than the 2nd element
// before applying Euclid's algorithm.
// The outer loop ensures that the maximum number of swaps are occurred.
// It ensures the implementation of the swapping process as many times
// as there are numbers in the array.
for (int i = 0; i < listofnum.size(); i++) {
// The inner loop performs the swapping.
for (int j = 1; j < listofnum.size(); j++) {
if (listofnum.get(j - 1) > listofnum.get(j)) {
int dummyvar = listofnum.get(j);
int dummyvar2 = listofnum.get(j - 1);
listofnum.set(j - 1, dummyvar);
listofnum.set(j, dummyvar2);
}
}
}
// nodup contains the array containing the userinput,without any
// duplicates.
ArrayList<Integer> nodup = new ArrayList();
// Remove duplicates.
for (int i = 0; i < listofnum.size(); i++) {
if (!nodup.contains(listofnum.get(i))) {
nodup.add(listofnum.get(i));
}
}
// Since the array is sorted in ascending order,we can easily determine
// which of the indexes has the bigger and smaller values.
small = nodup.get(0);
big = nodup.get(1);
remainder = big % small;
if (nodup.size() == 2) {
recursion(big, small, remainder);
} else if (nodup.size() > 2) {
largerlist(nodup, big, small, 2);
} else // In the case,the array only consists of one value.
{
System.out.println("GCD: " + nodup.get(0));
}
}
// recursive method.
public static int recursion(int big, int small, int remainder) {
remainder = big % small;
if (remainder == 0) {
System.out.println(small);
} else {
int dummyvar = remainder;
big = small;
small = dummyvar;
recursion(big, small, remainder);
}
return small;
}
// Method to deal with more than 2 numbers.
public static void largerlist(ArrayList<Integer> list, int big, int small, int counter) {
remainder = big % small;
gcd = recursion(big, small, remainder);
if (counter == list.size()) {
} else if (counter != list.size()) {
big = gcd;
small = list.get(counter);
counter++;
largerlist(list, gcd, small, counter);
}
}
}
I apologize in advance for any formatting errors etc.
Any suggestions would be appreciated.Thanks!
I think these two assignments are the wrong way around
big = gcd;
small = list.get(counter);
and then big not used
largerlist(list, gcd, small, counter);
Also you've used static variables, which is usually a problem.
I suggest removing static/global variables and generally don't reuse variables.
Edit: Oh yes, return. You've ignored the return value of the recursion method when called from the recursion method. That shouldn't matter as you are printing out instead of returning the value, but such solutions break when, say, you want to use the function more than once.
Related
I need a task about finding Fibonacci Sequence for my independent project in Java. Here are methods for find.
private static long getFibonacci(int n) {
switch (n) {
case 0:
return 0;
case 1:
return 1;
default:
return (getFibonacci(n-1)+getFibonacci(n-2));
}
}
private static long getFibonacciSum(int n) {
long result = 0;
while(n >= 0) {
result += getFibonacci(n);
n--;
}
return result;
}
private static boolean isInFibonacci(long n) {
long a = 0, b = 1, c = 0;
while (c < n) {
c = a + b;
a = b;
b = c;
}
return c == n;
}
Here is main method:
long key = getFibonacciSum(n);
System.out.println("Sum of all Fibonacci Numbers until Fibonacci[n]: "+key);
System.out.println(getFibonacci(n)+" is Fibonacci[n]");
System.out.println("Is n2 in Fibonacci Sequence ?: "+isInFibonacci(n2));
Codes are completely done and working. But if the n or n2 will be more than normal (50th numbers in Fib. Seq.) ? Codes will be runout. Are there any suggestions ?
There is a way to calculate Fibonacci numbers instantaneously by using Binet's Formula
Algorithm:
function fib(n):
root5 = squareroot(5)
gr = (1 + root5) / 2
igr = 1 - gr
value = (power(gr, n) - power(igr, n)) / root5
// round it to the closest integer since floating
// point arithmetic cannot be trusted to give
// perfect integer answers.
return floor(value + 0.5)
Once you do this, you need to be aware of the programming language you're using and how it behaves. This will probably return a floating point decimal type, whereas integers are probably desired.
The complexity of this solution is O(1).
Yes, one improvement you can do is to getFibonacciSum(): instead of calling again and again to isInFibonacci which re-calculates everything from scratch, you can do the exact same thing that isInFibonacci is doing and get the sum in one pass, something like:
private static int getFibonacciSum(int n) {
int a = 0, b = 1, c = 0, sum = 0;
while (c < n) {
c = a + b;
a = b;
sum += b;
b = c;
}
sum += c;
return sum;
}
Well, here goes my solution using a Map and some math formulas. (source:https://www.nayuki.io/page/fast-fibonacci-algorithms)
F(2k) = F(k)[2F(k+1)−F(k)]
F(2k+1) = F(k+1)^2+F(k)^2
It is also possible implement it using lists instead of a map but it is just reinventing the wheel.
When using Iteration solution, we don't worry about running out of memory, but it takes a lot of time to get fib(1000000), for example. In this solution we may be running out of memory for very very very very big inputs (like 10000 billion, idk) but it is much much much faster.
public BigInteger fib(BigInteger n) {
if (n.equals(BigInteger.ZERO))
return BigInteger.ZERO;
if (n.equals(BigInteger.ONE) || n.equals(BigInteger.valueOf(2)))
return BigInteger.ONE;
BigInteger index = n;
//we could have 2 Lists instead of a map
Map<BigInteger,BigInteger> termsToCalculate = new TreeMap<BigInteger,BigInteger>();
//add every index needed to calculate index n
populateMapWhitTerms(termsToCalculate, index);
termsToCalculate.put(n,null); //finally add n to map
Iterator<Map.Entry<BigInteger, BigInteger>> it = termsToCalculate.entrySet().iterator();//it
it.next(); //it = key number 1, contains fib(1);
it.next(); //it = key number 2, contains fib(2);
//map is ordered
while (it.hasNext()) {
Map.Entry<BigInteger, BigInteger> pair = (Entry<BigInteger, BigInteger>)it.next();//first it = key number 3
index = (BigInteger) pair.getKey();
if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
//index is divisible by 2
//F(2k) = F(k)[2F(k+1)−F(k)]
pair.setValue(termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
(((BigInteger.valueOf(2)).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).subtract(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)))))));
}
else {
//index is odd
//F(2k+1) = F(k+1)^2+F(k)^2
pair.setValue((termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE)))).add(
(termsToCalculate.get(index.divide(BigInteger.valueOf(2))).multiply(
termsToCalculate.get(index.divide(BigInteger.valueOf(2))))))
);
}
}
// fib(n) was calculated in the while loop
return termsToCalculate.get(n);
}
private void populateMapWhitTerms(Map<BigInteger, BigInteger> termsToCalculate, BigInteger index) {
if (index.equals(BigInteger.ONE)) { //stop
termsToCalculate.put(BigInteger.ONE, BigInteger.ONE);
return;
} else if(index.equals(BigInteger.valueOf(2))){
termsToCalculate.put(BigInteger.valueOf(2), BigInteger.ONE);
return;
} else if(index.remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
// index is divisible by 2
// FORMUMA: F(2k) = F(k)[2F(k+1)−F(k)]
// add F(k) key to termsToCalculate (the key is replaced if it is already there, we are working with a map here)
termsToCalculate.put(index.divide(BigInteger.valueOf(2)), null);
populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)));
// add F(k+1) to termsToCalculate
termsToCalculate.put(index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE), null);
populateMapWhitTerms(termsToCalculate, index.divide(BigInteger.valueOf(2)).add(BigInteger.ONE));
} else {
// index is odd
// FORMULA: F(2k+1) = F(k+1)^2+F(k)^2
// add F(k+1) to termsToCalculate
termsToCalculate.put(((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)),null);
populateMapWhitTerms(termsToCalculate,((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)).add(BigInteger.ONE)));
// add F(k) to termsToCalculate
termsToCalculate.put((index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)), null);
populateMapWhitTerms(termsToCalculate, (index.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2)));
}
}
This method of solution is called dynamic programming
In this method we are remembering the previous results
so when recursion happens then the cpu doesn't have to do any work to recompute the same value again and again
class fibonacci
{
static int fib(int n)
{
/* Declare an array to store Fibonacci numbers. */
int f[] = new int[n+1];
int i;
/* 0th and 1st number of the series are 0 and 1*/
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
/* Add the previous 2 numbers in the series
and store it */
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
public static void main (String args[])
{
int n = 9;
System.out.println(fib(n));
}
}
public static long getFib(final int index) {
long a=0,b=0,total=0;
for(int i=0;i<= index;i++) {
if(i==0) {
a=0;
total=a+b;
}else if(i==1) {
b=1;
total=a+b;
}
else if(i%2==0) {
total = a+b;
a=total;
}else {
total = a+b;
b=total;
}
}
return total;
}
I have checked all solutions and for me, the quickest one is to use streams and this code could be easily modified to collect all Fibonacci numbers.
public static Long fibonaciN(long n){
return Stream.iterate(new long[]{0, 1}, a -> new long[]{a[1], a[0] + a[1]})
.limit(n)
.map(a->a[0])
.max(Long::compareTo)
.orElseThrow();
}
50 or just below 50 is as far as you can go with straight recursive implementation. You can switch to iterative or dynamic programming (DP) approaches if you want to go much higher than that. I suggest learning about those from this: https://www.javacodegeeks.com/2014/02/dynamic-programming-introduction.html. And don't forget to look the a solution in the comment by David therein, real efficient. The links shows how even n = 500000 can be computed instantaneously using the DP method. The link also explains the concept of "memoization" to speed up computation by storing intermediate (but later on re-callable) results.
I am trying to solve a problem in which you have to count the number of possible bar codes you can make given specific parameters. I solved the problem recursively and am able to get the correct answer every time. However, my program is dreadfully slow. I tried to rectify this using a technique I read about called memoization but my program still crawls when given certain input (ex: 10, 10, 10). Here's the code in java.
Does anybody have any idea what I'm doing wrong here?
import java.util.Scanner;
//f(n, k, m) = sum (1 .. m) f(n - i, k - 1, m)
public class BarCode { public static int[][] memo;
public static int count(int units, int bars, int width) {
int sum = 0;
if (units >= 0 && memo[units][bars] != -1) //if the value has already been calculated return that value
return memo[units][bars];
for (int i = 1; i <= width; ++i) {
if (units == 0 && bars == 0)
return 1;
else if (bars == 0)
return 0;
else {
sum += count(units - i, bars - 1, width);
}
}
if (units > -1)
memo[units][bars] = sum;
return sum;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
//while (in.hasNext()) {
int num = in.nextInt();
int bars = in.nextInt();
int width = in.nextInt();
memo = new int[51][51];
for (int i = 0; i < memo.length; ++i) {
for (int j = 0; j < memo.length; ++j)
memo[i][j] = -1;
}
int sum = 0;
sum += count(num, bars, width);
System.out.println(sum);
//}
in.close();
}
}
TL:DR My memoization of a recursive search is too slow. Help!
You exclude all results from count calls with units < 0 from memoization:
if (units > -1)
memo[units][bars] = sum;
This leads to a lot of unnecessary calls to count for these values.
To include all cases, you could use a HashMap with a key generated from units and bars values. I used a string generated from units and bars like this:
//f(n, k, m) = sum (1 .. m) f(n - i, k - 1, m)
public class BarCode {
public static Map<String, Integer> memo = new HashMap<>();
public static int count(int units, int bars, int width) {
int sum = 0;
final String key = units + " " + bars;
Integer memoSum = memo.get(key);
if (memoSum != null) {
return memoSum.intValue();
}
for (int i = 1; i <= width; ++i) {
if (units == 0 && bars == 0)
return 1;
else if (bars == 0)
return 0;
else {
sum += count(units - i, bars - 1, width);
}
}
memo.put(key, Integer.valueOf(sum));
return sum;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int num = in.nextInt();
int bars = in.nextInt();
int width = in.nextInt();
memo = new HashMap<>();
int sum = 0;
sum += count(num, bars, width);
System.out.println(sum);
in.close();
}
}
For example, this brings the number of calls to count down from over 6 million to 4,150 for the input values "10 10 10" with 415 entries saved in the Map.
Your memoization implementation looks to be valid. It might help some, but the real problem here is your choice of algorithm.
From my cursory inspection of your code, on average a call to your count method will loop through width number of times. and each time it loops through, it goes a layer deeper by calling count again. It also looks like it's going to loop down bars layers deeper from the first layer. If my asymptotic analysis a few fingers of scotch in is correct, this would result in an algorithm which has a O(width^bars) runtime complexity. As you increase your input parameters, especially bars, the amount of steps your application needs to take in order to calculate your answer will increase greatly (exponentially, in the case of bars).
Your memoization will reduce the number of duplicate calculations needed, but each value being memoized will still need to be calculated at least once for the memoization to help. So with or without the memoization, you're still dealing with a non-polynomial time complexity, and that always spells bad performance.
You might want to consider looking for a more efficient approach. Instead of trying to count the number of bar code combinations, perhaps try using combinatorics to try to calculate it. For example, I could try to figure out the number of lowercase character strings (using only chars a-z) I can make for a string of length n by generating all of them and counting how many of them there are, but that will have an exponential time complexity and will not be performant. On the other hand, I know basic combinatorics tells me that the formula for the number of strings I can create is 26^n (26 choices in each position, and n positions), which the computer can easily evaluate quickly.
Look for a similar approach for computing the number of bar codes.
As the title reads, I have been thinking about creating multiple nested loops that aim to achieve one purpose. Move two generated random numbers between 0-9 through each possible possition of an array.
For example, App generates first number (fNum) 1 and second number (sNum) 6. It then moves these numbers in the array which containts ABC. However firstNum and secondNum will need to also try all the possible combinations, so each one will need to be different with each loop.
-1ABC6
-A1BC6
-AB1C6
-ABC16
-ABC61
-AB6C1
-A6BC1
-6ABC1
-A6B1C
-A61BC
-A16BC
-A1B6C
-A1BC6
and so on...
I beleive the best way will be to create a method for generating a counter, which increments the numbers which I can call.
private int getNextNumber(int num) {
if (num == 0) {
return num;
} else {
num++;
}
if (num < 10) {
return num;
} else {
return -1;
}
}
Then I will need multiple nested loops... I have decided to go for several loops which will go infinitly.
while (j < maxlen) {
//J = 0 and maxlen = length of text so in this case 3 as it is ABC
//Add two numbers and check against answer
while (fNum != -1 || sNum != -1) {
//incrememnt numbers
fNum = getNextNumber(fNum);
System.out.println(fNum);
sNum = getNextNumber(sNum);
System.out.println(fNum);
}
String textIni = "ABC";
int lenOfText = textIni.length();
char[] split = textIni.toCharArray();
for (int i = 0; i < lenOfText; i++) {
//here it will look at the length of the Text and
//try the possible positions it could be at....
//maybe wiser to do a longer loop but I am not too sure
}
}
Since you don't need to store all possible combinations, we will save some memory using only O(n) storage with an iterative solution. I propose you a basic implementation but don't expect to use it on large arrays since it has a O(n³) complexity.
public static void generateCombinationsIterative(List<Integer> original, int fnum, int snum) {
int size = original.size();
for (int i=0 ; i<=size ; i++) {
List<Integer> tmp = new ArrayList<>(original);
tmp.add(i,fnum);
for (int j=0 ; j<=size + 1 ; j++) {
tmp.add(j,snum);
System.out.print(tmp + (i == size && j == size + 1 ? "" : ", "));
tmp.remove(j);
}
}
}
For your culture, here is an example of a recursive solution, which takes a lot of memory so don't use it if you don't need to generate the lists of results. Nevertheless, this is a more general solution that can deal with any number of elements to insert.
public static List<List<Integer>> generateCombinations(List<Integer> original, Deque<Integer> toAdd) {
if (toAdd.isEmpty()) {
List<List<Integer>> res = new ArrayList<>();
res.add(original);
return res;
}
int element = toAdd.pop();
List<List<Integer>> res = new LinkedList<>();
for (int i=0 ; i<=original.size() ; i++)
// you must make a copy of toAdd, otherwise each recursive call will perform
// a pop() on it and the result will be wrong
res.addAll(generateCombinations(insertAt(original,element,i),new LinkedList<>(toAdd)));
return res;
}
// a helper function for a clear code
public static List<Integer> insertAt(List<Integer> input, int element, int index) {
List<Integer> result = new ArrayList<>(input);
result.add(index,element);
return result;
}
Note that I did not use any array in order to benefit from dynamic data structures, however you can call the methods like this :
int[] arr = { 1,2,3 };
int fnum = 4, snum = 5;
generateCombinationsIterative(Arrays.asList(arr),fnum,snum);
generateCombinations(Arrays.asList(arr),new LinkedList<>(Arrays.asList(fnum,snum));
Note that both methods generate the combinations in the same order.
I want to find the Nth number of the Recurrence Equation
T(n)=T(n-1)+3T(n-2)+3T(n-3)+(n-4),T(1)=T(4)=1,T(2)=T(3)=3
so if suppose you entered 2,5,9 as input, output should be T(2)=3,T(5)=20,T(9)=695
what I did is create an array of size equal to maximum of all input value and storing solution of T(i) at index i.Then look up into the array for specific index. eg array[3] for T(3),array[5] for T(5),etc
The code worked fine till maximum number is not greater than maximum integer value system can hold i.e
Integer.MAXValue.
Because the index of array can only be integer then
if number is n=1855656959555656 what should be the best way to find the solution of
T(1855656959555656)?
as clearly I cant create an array of size=1855656959555656..
I have even tried BigInteger from java.Math but with no success.
I have to find some other approach.please suggest some ideas..
Thanks
you do not need to store every T(i), you only need to store 3 values T(i-1), T(i-2), T(i-3). While looping over i, check if the current i should be part of your output, if so put it out immediately or save it to an "output"-array.
edit: this part is quite inefficient. You check in every iteation EVERY needed output.
for (int k = 0; k < arr.length; ++k) {
if (count == arr[k])
T[k] = temp[i];
else if (arr[k] == 1)
T[k] = 1;
else if (arr[k] == 2)
T[k] = 3;
else if (arr[k] == 3)
T[k] = 3;
else if (arr[k] == 4)
T[k] = 1;
}
so your code runs in time (max*arr.length) you can reduce it to only (max). Use a HashMap with key=neededPosition (=count) value=position in arr
Init the map like this:
Map<Long, Integer> map = new HashMap<Long, Integer>();
for (int i = 0; i < arr.length; i++) {
map.put(arr[i], i);
}
if (map.containsKey(count)) {
T[map.get(count)] = temp[i]
}
check the values 1-4 just once after the whole thing!
Not possible. The array size can be a maximum of Integer.MAX_VALUE (minus something usually 5 or 8, depending on the JVM capabilities). Why?. The index for an Array should be an integer thats a limitation.
It can't be done. So you need to solve the problem by introducing a sharding mechanism. The simplest way would be to just have arrays of arrays with a fixed length.
Edit: You really do not need this much storage for your problem at hand (as pointed out in another answer; this code fragment avoids arrays altogether to avoid bounds checks / indirection):
public void t(long n) {
if (n < 5) {
return (n == 2 || n == 3) ? 3 : 1;
}
long i = 5; // Initialize variables for n == 5;
long tn_1 = 1; // T(n-1) = T(4) = 1;
long tn_2 = 3; // T(n-2) = T(3) = 3;
long tn_3 = 1; // T(n-3) = T(2) = 1;
long tn_4 = 3; // T(n-4) = T(1) = 3;
while (true) {
long tn = tn_1 + 3*tn_2 + 3*tn_3 + tn_4;
if (i++ == n) {
return tn;
}
tn_4 = tn_3;
tn_3 = tn_2;
tn_2 = tn_1;
tn_1 = tn;
}
}
To answer the question in the title anyway:
If your array is sparse, use a map (TreeMap or HashMap) of Long or BigInteger:
Map<Long,Long> t = new TreeMap<Long,Long>()
The memory consumption of sparse arrays depends on the number of elements actually stored, so you may want to delete values from the map that are no longer needed.
If your array is not sparse, use a 2-level array (memory consumption will depend on the pre-allocated size only):
public class LongArray {
static final long BLOCK_SIZE = 0x40000000;
long[][] storage;
public LongArray(long size) {
long blockCount = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
storage = new long[][(int) blockCount];
for (long i = 0; i < blockCount; i++) {
if (i == blockCount - 1) {
storage[i] = new long[(int) size - BLOCK_SIZE * (blockCount - 1)];
} else {
storage[i] = new long[(int) BLOCK_SIZE];
}
}
}
public long get(long index) {
return storage[(int) (index / BLOCK_SIZE)][(int) (index % BLOCK_SIZE)];
}
public void put(long index, long value) {
storage[(int) (index / BLOCK_SIZE)][(int) (index % BLOCK_SIZE)] = value;
}
}
In both cases, use t.get(index) and t.put(index, value) instead of t[index] to access your array (if t is the name of the array).
You can do one thing. Check if the value of n is equal to 1855656959555656 in the beginning or if its multiple. Suppose, the value of n is twice of 1855656959555656. Then you can create two arrays and link them together virtually. This should solve your problem but it will involve a lot of overhead.
Use recursive call:
int T(int n){
if (n==1 || n==4){
return 1;
} else if (n==2 || n==3){
return 3;
} else {
return T(n-1)+3*T(n-2)+3T*(n-3)+T(n-4);
}
}
Edit: Time consumming. Won't work with large numbers
I was given a homework assignment in Java to create classes that find Prime number and etc (you will see in code better).
My code:
class Primes {
public static boolean IsPrime(long num) {
if (num%2==0){
return false;
}
for (int i=3; i*i<=num;i+=2) {
if (num%i==0) {
return false;
}
}
return true;
} // End boolen IsPrime
public static int[] primes(int min, int max){
int counter=0;
int arcount=0;
for (int i=min;i<max;i++){
if (IsPrime(i)){
counter++;
}
}
int [] arr= new int[counter];
for (int i=min;i<max;i++){
if (IsPrime(i)){
arr[arcount]=i;
arcount++;
}
}
return arr;
} // End Primes
public static String tostring (int [] arr){
String ans="";
for (int i=0; i<arr.length;i++){
ans= ans+arr[i]+ " ";
}
return ans;
}
public static int closestPrime(long num){
long e = 0 , d = 0 , f = num;
for (int i = 2; i <= num + 1 ; i++){
if ((num + 1) % i == 0){
if ((num + 1) % i == 0 && (num + 1) == i){
d = num + 1;
break;
}
num++;
i = 1;
}
}
num = f;
for (int i = 2; i < num; i++){
if ((num - 1) % i == 0){
if ((num - 1) % i == 0 && (num - 1) == i){
e = num - 1;
break;
}
num--;
i = 1;
}
}
num = f;
if (d - num < num - e) System.out.println("Closest Prime: "+d);
else System.out.println("Closest Prime: "+e);
return (int) num;
} // End closestPrime
}//end class
The goal of my code is to be faster (and correct). I'm having difficulties achieving this. Suggestions?
**New code:
class Primes {
public static boolean IsPrime(int num) {
if (num==1){
return false;
}
for (int i=2; i<Math.sqrt(num);i++) {
if (num%i==0) {
return false;
}
}
return true;
}
// End boolen IsPrime
public static int[] primes(int min, int max){
int size=0;
int [] arrtemp= new int[max-min];
for (int i=min;i<max;i++){
if (IsPrime(i)){
arrtemp[size]=i;
size++;
}
}
int [] arr= new int[size];
for (int i=0;i<size;i++){
arr[i]=arrtemp[i];
}
return arr;
}
public static String tostring (int [] arr){
String ans="";
for (int i=0; i<arr.length;i++){
ans= ans+arr[i]+ " ";
}
return ans;
}
public static int closestPrime(int num) {
int count=1;
for (int i=num;;i++){
int plus=num+count, minus=num-count;
if (IsPrime(minus)){
return minus;
}
if (IsPrime(plus)) {
return plus;
}
count=count+1;
}
} // End closestPrime
}//end class
I did try to make it a bit better. what do you think, it can be improved more? (the speed test is still high...)
In your primes function you:
Check if the current number is divisible by two
Check to see if it's prime
Create an array to put your output in.
Check every number in the range again for primality before putting it in your array.
The problem is in the last step. By double-checking whether each number is prime, you're duplicating your most expensive operations.
You could use a dynamic data structure and add prime numbers to it as you find them. That way you only need to check once.
Alternatively, you could create a boolean array which is the size of your input range. Then as you find primes, set the corresponding array value to true.
UPDATE:
There are still a number of improvements you can make, but some will require more work than others to implement. Look at the specifics of your test and see what fits your needs.
Low-hanging fruit:
Use an ArrayList to collect primes as you find them in primes, as opposed to looping over the values twice.
In closestPrime, you're checking every single value on either side of num: half of these are even, thus not prime. You could adapt your code to check only odd numbers for primality.
Trickier to implement:
Try a more advanced algorithm for IsPrime: check out the Sieve of Eratosthenes
Above all, you should spend some time figuring out exactly where the bottlenecks are in your code. Oftentimes performance problems are caused by code we thought was perfectly fine. You might consider looking into the code-profiling options available in your development environment.
You make quite a few calls to isPrime(), each of which is very expensive. Your first step should be to minimize the number of times you do that, since the result doesn't change for any given number, there's no point calling more than once. You can do this with memoization by storing the values once they're computed:
ArrayList<Integer> memoList = new ArrayList<Integer>();
for(int i = 0; i < max; i++) {
if(isPrime(i)) {
memoList.add(i);
}
}
Now memoList holds all the primes you need, up to max, and you can loop over them rapidly without needing to recompute them every time.
Secondly, you can improve your isPrime() method. Your solution loops over every odd number from 3 to sqrt(n), but why not just loop over the primes, now that we know them?
public static boolean IsPrime(long num) {
for(int p : memoList) {
if(num % p == 0) {
return false;
}
}
return true;
}
These changes should dramatically improve how quickly your code runs, but there has been a lot of research into even more efficient ways of calculating primes. The Wikipedia page on Prime Numbers has some very good information on further tactics (prime sieves, in particular) you can experiment with.
Remember that as this is homework you should be sure to cite this page when you turn it in. You're welcome to use and expand upon this code, but not citing this question and any other resources you use is plagiarism.
I see a couple problems with your answer. First, 2 is a prime number. Your first conditional in IsPrime breaks this. Second, in your primes method, you are cycling through all number from min to max. You can safely ignore all negative numbers and all even numbers (as you do in IsPrime). It would make more sense to combine these two methods and save all the extra cycles.