Dead code warning in the i-- - java

I'm going to try to define function which return greatest common divisor.
Now I'm just meeting some obstacle.
Why do dead code warning appear in the i--?
I can feel nothing so please let me know what is wrong.
public class Main {
public static int function(int a, int b, int c) {
int min;
if (a > b) {
if (b > c) {
min = c;
} else {
min = b;
}
} else {
if (a > c) {
min = c;
} else {
min = a;
}
}
for (int i = min; i > 0; i--) {
if (a % i == 0 && b % i == 0 && c % i == 0) {
return i;
}
return -1;
}
return 0;
}
public static void main(String[] args) {
System.out.println("(400, 300, 750)의 최대 공약수 : " + function(400, 300, 750));
}
}

The for loop has an if block where you are returning the greatest common divisor if found. If not you are returning -1. So the loop will never continue and "i--" will never be executed. That is why it's a dead code. Remove "return -1", it should work properly.

Stepping through the code in your debugger is often the quickest way to find these bugs. However, you could make the code much faster by only checking values which are a factor of the min value. This reduces the number of iterations dramatically.
public class Main {
public static int function(int a, int b, int c) {
int min;
if (a > b) {
if (b > c) {
min = c;
} else {
min = b;
}
} else {
if (a > c) {
min = c;
} else {
min = a;
}
}
for (int i = min; i > 0; i--) {
if (a % i == 0 && b % i == 0 && c % i == 0) {
System.err.println("Iterations " + (min + 1 - i));
return i;
}
}
return 0;
}
public static long gcd(long a, long b, long c) {
long min = Math.min(a, Math.min(b, c));
for (int j = 1, max = (int) Math.sqrt(min); j <= max; j++) {
long i = min / j;
if (a % i == 0 && b % i == 0 && c % i == 0) {
System.err.println("Iterations: " + j);
return i;
}
}
return 1;
}
public static void main(String[] args) {
System.out.println("(400, 300, 750)의 최대 공약수 : " + function(400, 300, 750));
System.out.println("(400, 300, 750)의 최대 공약수 : " + gcd(400, 300, 750));
}
}
prints
(400, 300, 750)의 최대 공약수 : 50
(400, 300, 750)의 최대 공약수 : 50
Iterations 251
Iterations: 6
In your approach, it has to consider all the factors from 300 to 50 (251 values). But considering only the factors of 300 i.e. 300/1, 300/2, 300/3, 300/4, 300/5, 300/6 (6 values) it is much faster.

Related

fibonacci and prime numbers in one series

I am trying to do some mock questions of coding for an entrance exam, I came about this question and I am stuck at the PRIME NUMBERS part.
Here is the question:
Consider the below series: 1, 2, 1, 3, 2, 5, 3, 7, 5, 11, 8, 13, 13, 17, … This series is a mixture of 2 series – all the odd terms in this series form a Fibonacci series and all the even terms are the prime numbers in ascending order. Write a program to find the Nth term in this series. For example, when N = 14, the 14th term in the series is 17. So only the value 17 should be printed out.
public class OandF {
// main
public static void main(String[] args) {
System.out.println(dofibo(9));
}
public static int dofibo(int m) {
if(m == 0) {
return 0;
}
if(m == 1) {
return 1;
}
return dofibo(m-1) + dofibo(m-2);
}
}
// as you can see this is where I got to, and I don't know how to proceed
There are multiple ways to find the nth Prime number, the easiest way is to keep counting the prime numbers from 1 to n. But this is very time consuming otherwise refer to Fermat's theorems or Sieve of Eratosthenes.
private boolean isPrime(int n) {
if (n == 2 || n == 3) return true;
for(int i = 2; i < (int)Math.sqrt(n) + 1; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public int nthPrime(int n) {
int number, primeCount;
for(number = 2, primeCount = 0; primeCount < n; number++) {
if (isPrime(number)) {
++primeCount;
}
}
return number;
}
You can try this, it may solve your problem.
class FibonacciExample1 {
public static void main(String args[]) {
int input = 20;
fibonacci(input);
System.out.print("-----------------------------");
prime(input);
}
public static void fibonacci(int input) {
int n1 = 0, n2 = 1, n3, i, count = input;
System.out.print(n1 + " " + n2);
for (i = 2; i < count; ++i) {
n3 = n1 + n2;
System.out.print(" " + n3);
n1 = n2;
n2 = n3;
}
}
public static void prime(int input) {
int i = 0;
int num = 0;
String primeNumbers = "";
for (i = 1; i <= input; i++) {
int counter = 0;
for (num = i; num >= 1; num--) {
if (i % num == 0) {
counter = counter + 1;
}
}
if (counter == 2) {
primeNumbers = primeNumbers + i + " ";
}
}
System.out.println(primeNumbers);
}
}
I'd make these two programs into simpler, infinite generators that are easier to debug and then sequence:
import java.util.ArrayList;
class Fibonacci {
int a = 0, b = 1;
int next() {
int c = a;
a = b;
b += c;
return a;
}
}
class Prime {
ArrayList<Integer> primes = new ArrayList<>();
int number = 2;
int next() {
if (number == 2) { // special case
primes.add(number);
number = 1;
return 2;
}
outer: while (true) {
number += 2;
for (int divisor: primes) {
if (divisor * divisor > number) {
break outer;
}
if (number % divisor == 0) {
break;
}
}
}
primes.add(number);
return number;
}
}
public class Example {
public static int sequence(int n) {
int nth = -1;
if ((n % 2) == 0) {
Fibonacci fibonacci_generator = new Fibonacci();
for (int i = 0; i < (n / 2) + 1; i++) {
nth = fibonacci_generator.next();
}
} else {
Prime prime_generator = new Prime();
for (int i = 0; i < (n + 1) / 2; i++) {
nth = prime_generator.next();
}
}
return nth;
}
public static void main(String args[]) {
System.out.println(sequence(13)); // 14th element counting from zero
}
}

Why was the memory limit exceeded and how can I avoid this?

Code
import java.util.*;
public class AlmostPerfect {
public static void main(String[] args) {
Scanner x = new Scanner(System.in);
while(x.hasNext()) {
int n = x.nextInt();
int sum = recursion(n, n-1, 0);
if (sum == n) {
System.out.println(n + " perfect");
} else if ((n - sum) <= 2) {
System.out.println(n + " almost perfect");
} else {
System.out.println(n + " not perfect");
}
}
}
public static int recursion(int n, int x,int sum) {
if(x == 0){
return sum;
}
else if (n % x == 0) {
sum += x;
return recursion(n, x-1, sum);
}
else{
return recursion(n, x-1, sum);
}
}
}
I want to basically find what's wrong with my solution... There exists a solution for this, but I can't understand the memory limit exceeded property.
Problem link: https://open.kattis.com/problems/almostperfect
If you must prefer a recursive solution, you can limit the depth of the recursion, to avoid stack overflow.
You can do it be running the recursive solution on continuous intervals, one interval at time:
import java.util.stream.IntStream;
public class AlmostPerfect {
// Defines the recursive iteration depth. increase it and you run into
// Stack overflow
private static int RECURSION_DEPTH = 5000;
public static void main(String[] args) {
// Run comparison test between recursive and non recursive solutions
IntStream.range(1, 200000).forEach(i -> {
double sumRecursive = recursionWithLimitedDepth(i);
double sumIterative = iterative(i);
if((sumRecursive != sumIterative)) {
System.out.println("for " + i + " " + sumRecursive + "<>" + sumIterative);
return;
}
if((i%20000) == 0) {
System.out.println("20,000 numbers successfully checked");
}
});
System.out.println("Test finished");
}
// Helper method for recursive solution
public static double recursionWithLimitedDepth(int n) {
double sum = 0;
int rangeStart = n-1;
int rangeEnd = rangeStart - RECURSION_DEPTH;
while (rangeStart > 0) {
sum += recursionWithLimitedDepth(n, rangeStart, rangeEnd, 0);
rangeStart = (rangeEnd - 1) >= 0 ? rangeEnd - 1 : 0;
rangeEnd = (rangeStart - RECURSION_DEPTH) >= 0 ? rangeStart - RECURSION_DEPTH : 0;
}
return sum;
}
// Run recursive solution on a limited range defined by rangeStart, rangeEnd
public static double recursionWithLimitedDepth(int numberToTest, int rangeStart,
int rangeEnd, double sum) {
if(rangeStart == 0) {
return sum;
}
else if ((numberToTest % rangeStart) == 0) {
sum += rangeStart;
}
if(rangeStart == rangeEnd) {
return sum;
}
return recursionWithLimitedDepth(numberToTest, rangeStart-1, rangeEnd, sum);
}
// Simple iterative to test against
public static double iterative(int n) {
double sum = 0;
for(int x = n-1; x > 0; x--) {
if((n%x) == 0) {
sum += x;
}
}
return sum;
}
}
Note that sum is double to avoid Integer overflow (tested with Integer.MAX_VALUE).

Miller-Rabin Primality Test Often Returns Composite for Prime Numbers

I have been trying to implement a Miller-Rabin primality test from scratch (only primitives and Strings) that works for 64 bit integers (longs). I've tried the Java and pseudocode from Wikipedia, as well as various other websites. So far, only very small numbers have worked correctly. Most numbers are incorrectly marked composite, such as 53 or 101. I have tried tracking various sections of the code to see where the problem is. It seems to be in the innermost loop. I don't know what the specific issue is. Any help is appreciated. Thanks!
Here is my code:
public class PrimeTest
{
public static void main(String[] args)
{
PrimeTest app = new PrimeTest();
}
private PrimeTest()
{
long n = 53; // Change to any number. 53 is prime, but is reported as composite
if (checkPrime(n, 10))
{
System.out.println(n + " is prime.");
}
else
{
System.out.println(n + " is not prime.");
}
}
// Check if n is prime with 4^(-k) change of error
private boolean checkPrime(long n, int k)
{
// Factor n-1 as d*2^s
long d = n - 1;
int s = 0;
while (d % 2 == 0)
{
d /= 2;
s++;
}
// Repeat k times for 4^-k accuracy
for (int i = 0; i < k; i++)
{
long a = (long) ((Math.random() * (n - 3)) + 2);
long x = modPow(a, d, n);
if (x == 1 || x == (n - 1))
{
continue;
}
int r;
for (r = 0; r < s; r++)
{
x = modPow(x, 2, n);
if (x == 1)
{
return false;
}
if (x == (n - 1))
{
break;
}
}
if (r == s)
{
return false;
}
}
return true;
}
// Return (base^exp) % mod
private long modPow(long base, long exp, long mod)
{
if (mod == 1)
{
return 0;
}
long result = 1;
base = base % mod;
while (exp > 0)
{
if ((exp & 1) == 0)
{
result = (result * base) % mod;
}
exp = exp >> 1;
base = (base * base) % mod;
if (base == 1)
{
break;
}
}
return result;
}
}
This line in modPow:
if ((exp & 1) == 0)
is wrong and should instead be
if ((exp & 1) == 1)

Optimize Collatz Conjecture in Java

I'm working on a program that determines the number of steps it takes for a number to become 1 using the Collatz Conjecture (if n is odd, 3n+1; if n is even, n/2). The program increases the number being calculated by one each time it completes a calculation, and tests how many numbers it can calculate in seconds. Here is the working program I currently have:
public class Collatz {
static long numSteps = 0;
public static long calculate(long c){
if(c == 1){
return numSteps;
}
else if(c % 2 == 0){
numSteps++;
calculate(c / 2);
}
else if(c % 2 != 0){
numSteps++;
calculate(c * 3 + 1);
}
return numSteps;
}
public static void main(String args[]){
int n = 1;
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() < startTime + 60000){
calculate(n);
n++;
numSteps = 0;
}
System.out.println("The highest number was: " + n);
}
}
It can currently calculate about 100 million numbers in a minute, but I'm looking for advice on how to further optimize the program so that it can calculate more numbers in a minute. Any and all advice would be appreciated :).
You can
optimise the calculate method by assuming that is c % 2 == 0 is false than c % 2 != 0 must be true. You can also assume that c * 3 + 1 must be an even number so you can calculate (c * 3 + 1)/2 and add two to the numSteps. You can use a loop instead of recursion as Java doesn't have tail-call optimisation.
get a bigger improvement by using memorisation. For each each number you can memorise the result you get and if the number has been calculated before just return that value. You might want to place an upper bound on memorization e.g. no higher than the last number you want to calculate. If you don't do this some of the value will be many times the largest value.
For your interest
public class Collatz {
static final int[] CALC_CACHE = new int[2_000_000_000];
static int calculate(long n) {
int numSteps = 0;
long c = n;
while (c != 1) {
if (c < CALC_CACHE.length) {
int steps = CALC_CACHE[(int) c];
if (steps > 0) {
numSteps += steps;
break;
}
}
if (c % 2 == 0) {
numSteps++;
c /= 2;
} else {
numSteps += 2;
if (c > Long.MAX_VALUE / 3)
throw new IllegalStateException("c is too large " + c);
c = (c * 3 + 1) / 2;
}
}
if (n < CALC_CACHE.length) {
CALC_CACHE[(int) n] = numSteps;
}
return numSteps;
}
public static void main(String args[]) {
long n = 1, maxN = 0, maxSteps = 0;
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() < startTime + 60000) {
for (int i = 0; i < 10; i++) {
int steps = calculate(n);
if (steps > maxSteps) {
maxSteps = steps;
maxN = n;
}
n++;
}
if (n % 10000000 == 1)
System.out.printf("%,d%n", n);
}
System.out.printf("The highest number was: %,d, maxSteps: %,d for: %,d%n", n, maxSteps, maxN);
}
}
prints
The highest number was: 1,672,915,631, maxSteps: 1,000 for: 1,412,987,847
A more advanced answer would be to use multiple threads. In this case using recursion with memorisation was easier to implement.
import java.util.stream.LongStream;
public class Collatz {
static final short[] CALC_CACHE = new short[Integer.MAX_VALUE-8];
public static int calculate(long c) {
if (c == 1) {
return 0;
}
int steps;
if (c < CALC_CACHE.length) {
steps = CALC_CACHE[(int) c];
if (steps > 0)
return steps;
}
if (c % 2 == 0) {
steps = calculate(c / 2) + 1;
} else {
steps = calculate((c * 3 + 1) / 2) + 2;
}
if (c < CALC_CACHE.length) {
if (steps > Short.MAX_VALUE)
throw new AssertionError();
CALC_CACHE[(int) c] = (short) steps;
}
return steps;
}
static int calculate2(long n) {
int numSteps = 0;
long c = n;
while (c != 1) {
if (c < CALC_CACHE.length) {
int steps = CALC_CACHE[(int) c];
if (steps > 0) {
numSteps += steps;
break;
}
}
if (c % 2 == 0) {
numSteps++;
c /= 2;
} else {
numSteps += 2;
if (c > Long.MAX_VALUE / 3)
throw new IllegalStateException("c is too large " + c);
c = (c * 3 + 1) / 2;
}
}
if (n < CALC_CACHE.length) {
CALC_CACHE[(int) n] = (short) numSteps;
}
return numSteps;
}
public static void main(String args[]) {
long maxN = 0, maxSteps = 0;
long startTime = System.currentTimeMillis();
long[] res = LongStream.range(1, 6_000_000_000L).parallel().collect(
() -> new long[2],
(long[] arr, long n) -> {
int steps = calculate(n);
if (steps > arr[0]) {
arr[0] = steps;
arr[1] = n;
}
},
(a, b) -> {
if (a[0] < b[0]) {
a[0] = b[0];
a[1] = b[1];
}
});
maxN = res[1];
maxSteps = res[0];
long time = System.currentTimeMillis() - startTime;
System.out.printf("After %.3f seconds, maxSteps: %,d for: %,d%n", time / 1e3, maxSteps, maxN);
}
}
prints
After 52.461 seconds, maxSteps: 1,131 for: 4,890,328,815
Note: If I change the second calculate call to
steps = calculate((c * 3 + 1) ) + 1;
it prints
After 63.065 seconds, maxSteps: 1,131 for: 4,890,328,815

How to find the GCD of three numbers within a single method

I've got to ensure that the GCD between 3 numbers is no greater than 1.
Here's the code I have so far for the method:
private int greatestCommonFactor(int a, int b, int c)
{
for(int n = 0; n <= number; n++)
{
if()
}
return 1;
}
the return 1 was already there when I started working on the lab. How can I make sure that the GCD is no more than 1? And return all three integers?
Here's the remainder of the code if it helps in figuring out what needs to be done:
import static java.lang.System.*;
public class Triples
{
private int number;
public Triples()
{
this(0);
}
public Triples(int num)
{
number = num;
}
public void setNum(int num)
{
number = num;
}
private int greatestCommonFactor(int a, int b, int c)
{
for(int n = 0; n <= number; n++)
{
if()
}
return 1;
}
public String toString()
{
String output="";
int max = number;
for(a = 1; a <= max; a++)
{
for(b = a +1; b <= max; b++)
{
for(c = b + 1; c <= max; c++)
{
if(Math.pow(a, 2)+ Math.pow(b, 2)== Math.pow(c, 2))
{
if((a%2==1 && b%2==0)|| (a%2==0 && b%2==1))
}
}
}
}
return output+"\n";
}
}
UPDATE
Here is my new coding for the same lab:
import static java.lang.System.*;
public class Triples
{
private int number;
public Triples()
{
this(0);
}
public Triples(int num)
{
number = num;
}
public void setNum(int num)
{
number = num;
}
private int greatestCommonFactor(int a, int b, int c)
{
for(int n = 0; n <= number; n++)
{
int max = number;
for(a = 1; a <= max; a++)
{
a = n;
for(b = a +1; b <= max; b++)
{
b =n;
for(c = b + 1; c <= max; c++)
{
c = n;
if(Math.pow(a, 2)+ Math.pow(b, 2)== Math.pow(c, 2))
{
if((a%2==1 && b%2==0)|| (a%2==0 && b%2==1))
{
if(a%2<=1 && b%2<=1 && c%2<=1)
{
return 1;
}
}
}
}
}
}
}
return 1;
}
public String toString()
{
String output="";
output = greatestCommonFactor(a, b, c);
return output+"\n";
}
}
You can use Euclid's algorithm to calculate the GCD of a and b. Call the result d. Then the GCD of a, b, and c is the GCD of c and d; for that, you can use Euclid's algorithm again.
Here's a brute-force way if you don't care about efficiency:
private int greatestCommonFactor(int a, int b, int c)
{
limit = Math.min(a, b);
limit = Math.min(limit, c);
for(int n = limit; n >= 2; n--)
{
if ( (a % n == 0) && (b % n == 0) && (c % n == 0) ) {
return n;
}
}
return 1;
}
Explanation:
You can save some work by only checking up to the minimum of (a, b, c). Any number greater than that definitely won't be a GCD of all 3.
You need to start your loop at n = limit instead of n = 0 and count backwards.
As soon as we come across a number that produces zero remainder for (a, b, c), that must be the GCD.
If nothing is found within the loop, GCD defaults to 1.

Categories

Resources