Java For Loop conditional test - java

I'm sure this is a very basic question but having trouble understanding why the below FOR loop works?
The code below brings back a set number of Primes and works as it should. I understand the whole math reasoning behind using square root, however my issue is more with the conditional part of the FOR statement.
The first argument that is fed into isPrime() to check is 2 which of course is Prime. The first isPrime() gets the square root of 2 which is ~ 1.4.
At this point, I get confused. Starting at i = 2 which is obviously > 1.4 so than the starting condition of i <= root (ie 2 <= 1.4) has NOT been met. The IF statement should not run and it should return no result, but it does.
It doesn't seem to me like I should get any result back until I get to 5 because 2 is also > than the square root of 3. I'm obviously not understating either the initialization or conditional aspect of the FOR statement here? Can someone please help me with the logic?
class BooleanTest{
public static void main(String[] arguments) {
int quantity = 10;
int numPrimes = 0;
int candidate = 2; //starting prime #
System.out.println("First " + quantity + " primes:");
while (numPrimes < quantity) {
if (isPrime(candidate)) { //if isPrime Method true
System.out.println(candidate);
numPrimes++;
}
candidate++;
}
}
public static boolean isPrime(int checkNumber) {
double root = Math.sqrt(checkNumber); //get square root of candidate
for (int i = 2; i <= root; i++) {
if (checkNumber % i == 0) { //if remainder of candidate/i = 0
return false; //because candidate is not prime. has factor other than 1 and self.
}
return true;
}
}

For inputs 1, 2, 3 the loop will not execute at all, indeed. As a result, the return false statement in the body of the loop will not be executed as well. Instead the return true statement right after the loop will get executed and the result of the method call will be true for these inputs.
The first number for which the loop will execute is 4 and the method will correctly return false as 4 is divideable by 2.
Fixing the indentation of the code makes this behavior a bit easier to see:
public static boolean isPrime(int checkNumber) {
double root = Math.sqrt(checkNumber); //get square root of candidate
for (int i = 2; i <= root; i++) {
if (checkNumber % i == 0) { //if remainder of candidate/i = 0
return false; //because candidate is not prime. has factor other than 1 and self.
}
}
return true;
}

root is not initialized to sqrt(2), it's initialized to sqrt(checkNumber), which would be larger than 2 for most inputs. Therefore your So than the starting condition of i <= root (ie 2 <= 1.4) has NOT been met so then the IF statement should not run and I would get no result back assumption is false.

Related

How to find the 5th perfect number (which is 33550336)? The problem is taking forever to run

I am trying to write a Java method that checks whether a number is a perfect number or not.
A perfect number is a number that is equal to the sum of all its divisor (excluding itself).
For example, 6 is a perfect number because 1+2+3=6. Then, I have to write a Java program to use the method to display the first 5 perfect numbers.
I have no problem with this EXCEPT that it is taking forever to get the 5th perfect number which is 33550336.
I am aware that this is because of the for loop in my isPerfectNumber() method. However, I am very new to coding and I do not know how to come up with a better code.
public class Labreport2q1 {
public static void main(String[] args) {
//Display the 5 first perfect numbers
int counter = 0,
i = 0;
while (counter != 5) {
i++;
isPerfectNumber(i);
if (isPerfectNumber(i)) {
counter++;
System.out.println(i + " ");
}
}
}
public static boolean isPerfectNumber(int a) {
int divisor = 0;
int sum = 0;
for (int i = 1; i < a; i++) {
if (a % i == 0) {
divisor = i;
sum += divisor;
}
}
return sum == a;
}
}
This is the output that is missing the 5th perfect number
Let's check the properties of a perfect number. This Math Overflow question tells us two very interesting things:
A perfect number is never a perfect square.
A perfect number is of the form (2k-1)×(2k-1).
The 2nd point is very interesting because it reduces our search field to barely nothing. An int in Java is 32 bits. And here we see a direct correlation between powers and bit positions. Thanks to this, instead of making millions and millions of calls to isPerfectNumber, we will be making less than 32 to find the 5th perfect number.
So we can already change the search field, that's your main loop.
int count = 0;
for (int k = 1; count < 5; k++) {
// Compute candidates based on the formula.
int candidate = (1L << (k - 1)) * ((1L << k) - 1);
// Only test candidates, not all the numbers.
if (isPerfectNumber(candidate)) {
count++;
System.out.println(candidate);
}
}
This here is our big win. No other optimization will beat this: why test for 33 million numbers, when you can test less than 100?
But even though we have a tremendous improvement, your application as a whole can still be improved, namely your method isPerfectNumber(int).
Currently, you are still testing way too many numbers. A perfect number is the sum of all proper divisors. So if d divides n, n/d also divides n. And you can add both divisors at once. But the beauty is that you can stop at sqrt(n), because sqrt(n)*sqrt(n) = n, mathematically speaking. So instead of testing n divisors, you will only test sqrt(n) divisors.
Also, this means that you have to start thinking about corner cases. The corner cases are 1 and sqrt(n):
1 is a corner case because you if you divide n by 1, you get n but you don't add n to check if n is a perfect number. You only add 1. So we'll probably start our sum with 1 just to avoid too many ifs.
sqrt(n) is a corner case because we'd have to check whether sqrt(n) is an integer or not and it's tedious. BUT the Math Overflow question I referenced says that no perfect number is a perfect square, so that eases our loop condition.
Then, if at some point sum becomes greater than n, we can stop. The sum of proper divisors being greater than n indicates that n is abundant, and therefore not perfect. It's a small improvement, but a lot of candidates are actually abundant. So you'll probably save a few cycles if you keep it.
Finally, we have to take care of a slight issue: the number 1 as candidate. 1 is the first candidate, and will pass all our tests, so we have to make a special case for it. We'll add that test at the start of the method.
We can now write the method as follow:
static boolean isPerfectNumber(int n) {
// 1 would pass the rest because it has everything of a perfect number
// except that its only divisor is itself, and we need at least 2 divisors.
if (n < 2) return false;
// divisor 1 is such a corner case that it's very easy to handle:
// just start the sum with it already.
int sum = 1;
// We can stop the divisors at sqrt(n), but this is floored.
int sqrt = (int)Math.sqrt(n);
// A perfect number is never a square.
// It's useful to make this test here if we take the function
// without the context of the sparse candidates, because we
// might get some weird results if this method is simply
// copy-pasted and tested on all numbers.
// This condition can be removed in the final program because we
// know that no numbers of the form indicated above is a square.
if (sqrt * sqrt == n) {
return false;
}
// Since sqrt is floored, some values can still be interesting.
// For instance if you take n = 6, floor(sqrt(n)) = 2, and
// 2 is a proper divisor of 6, so we must keep it, we do it by
// using the <= operator.
// Also, sqrt * sqrt != n, so we can safely loop to sqrt
for (int div = 2; div <= sqrt; div++) {
if (n % div == 0) {
// Add both the divisor and n / divisor.
sum += div + n / div;
// Early fail if the number is abundant.
if (sum > n) return false;
}
}
return n == sum;
}
These are such optimizations that you can even find the 7th perfect number under a second, on the condition that you adapt the code for longs instead of ints. And you could still find the 8th within 30 seconds.
So here's that program (test it online). I removed the comments as the explanations are here above.
public class Main {
public static void main(String[] args) {
int count = 0;
for (int k = 1; count < 8; k++) {
long candidate = (1L << (k - 1)) * ((1L << k) - 1);
if (isPerfectNumber(candidate)) {
count++;
System.out.println(candidate);
}
}
}
static boolean isPerfectNumber(long n) {
if (n < 2) return false;
long sum = 1;
long sqrt = (long)Math.sqrt(n);
for (long div = 2; div <= sqrt; div++) {
if (n % div == 0) {
sum += div + n / div;
if (sum > n) return false;
}
}
return n == sum;
}
}
The result of the above program is the list of the first 8 perfect numbers:
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
You can find further optimization, notably in the search if you check whether 2k-1 is prime or not as Eran says in their answer, but given that we have less than 100 candidates for longs, I don't find it useful to potentially gain a few milliseconds because computing primes can also be expensive in this program. If you want to check for bigger perfect primes, it makes sense, but here? No: it adds complexity and I tried to keep these optimization rather simple and straight to the point.
There are some heuristics to break early from the loops, but finding the 5th perfect number still took me several minutes (I tried similar heuristics to those suggested in the other answers).
However, you can rely on Euler's proof that all even perfect numbers (and it is still unknown if there are any odd perfect numbers) are of the form:
2i-1(2i-1)
where both i and 2i-1 must be prime.
Therefore, you can write the following loop to find the first 5 perfect numbers very quickly:
int counter = 0,
i = 0;
while (counter != 5) {
i++;
if (isPrime (i)) {
if (isPrime ((int) (Math.pow (2, i) - 1))) {
System.out.println ((int) (Math.pow (2, i -1) * (Math.pow (2, i) - 1)));
counter++;
}
}
}
Output:
6
28
496
8128
33550336
You can read more about it here.
If you switch from int to long, you can use this loop to find the first 7 perfect numbers very quickly:
6
28
496
8128
33550336
8589869056
137438691328
The isPrime method I'm using is:
public static boolean isPrime (int a)
{
if (a == 1)
return false;
else if (a < 3)
return true;
else {
for (int i = 2; i * i <= a; i++) {
if (a % i == 0)
return false;
}
}
return true;
}

Recursion - Finding the Amount of Even Digits in a Number

I'm having trouble with this problem. I am supposed to find the amount of even digits in a number.
So for example, if the number is 146, then there are 2 even digits.
And if the number is 802, then there are 3 even digits.
I was told that n % 10 is the value of the rightmost digit. n / 10 contains all of the digits except the rightmost digit.
public static int countEvenDigits(int n) {
int rightDigit = n % 10;
int count= 0;
if (rightDigit / 10 == 0) {
count++;
}
return countEvenDigits(count);
}
With recursion, you can do it like this
int calcRec(int num) {
if (num / 10 == 0) {
return num % 2 == 0 ? 1 : 0;
}else{
return (num % 10 % 2 == 0? 1:0)+calcRec(num/10);
}
}
But its not suitable case for using recursion.
Another answer:
public static int countEvenDigits(int number) {
if (number == 0) return 0;
int lastDigit = number % 10;
int firstDigits = number / 10;
if (lastDigit % 2 == 0) {
return 1 + countEvenDigits(firstDigits);
} else {
return 0 + countEvenDigits(firstDigits);
}
}
Recursion always needs one or more "base case"s, where recursion stops (in this case, no digits left); and one or more "recursive cases" where you continue to work with a smaller problem (with the firstDigits).
I agree with #kimreik that this is not a good use of recursion (as the problem could be better solved with a while-loop); but it is a very typical example when starting to learn to program recursion, as I suspect the OP is doing.
Ok so the idea of using recursion to process a series is that you define a function that process and removes one element from the set. Seeing as you are interested in digits you have 2 options to define your set from a given int.
The first option is to cast the int to a string and cast each character back into an int. Which is what I implemented below
Alternatively you could do division by your base (10) to the power of the significance of the digit (0 being the right most digit and counting left.) Or more eloquently as kimreik reducing the number by integer division sequentially. (142 / 10 / 10 == 142 / 100 == 1 == "142"[0])...
The syntax for converting your integer to a string is Integer.toString(int). This will be useful as it allows us to access each digit without doing any math and also allows us to take sub-strings which we can pass to the next instance of our recursive method.
Now that we have our array to process we need to address the fundamentals of recursion. Recursion has three parts. These parts are as follows, some starting state or initial values, a base case and a recursive step.
For this problem we must set our initial values for the count of even digits and we will be given a string to process. We will start our count at 0 but it will be a variable passed to each call to our method.
Our base case is the empty sting, that is a blank number. Which contains 0 even numbers. Because we are recurring towards an empty set this type of algorithm is called reductive.
Now our recursive step is where everything really happens. It must read a digit from our string and then remove it from the string by passing the remaining digits to the next instance of the function.
Now that we know what we need to do what does out function look like?
public class HelloWorld{
public static int recursiveGetEvenDigits(String arg){
int count = 0;
if(arg.length()<1){
return(0); // base case
}
else{
count = Character.getNumericValue(arg.charAt(0))%2 == 0 ? 1 : 0; //If else shorthand
return(count+recursiveGetEvenDigits(arg.substring(1)));
}
}
public static int getEvenDigits(int n){ // provide user arguments
return(recursiveGetEvenDigits(Integer.toString(n))); // set initial conditions
}
public static void main(String []args){
System.out.println(getEvenDigits(142));
}
}
Just to be funny the whole if else logic could be reduced to one line again with the same shorthand I used above.
public class HelloWorld{
public static int recursiveGetEvenDigits(String arg){
return arg.length() < 1 ? 0 : (Character.getNumericValue(arg.charAt(0)) % 2 == 0 ? 1 : 0)+recursiveGetEvenDigits(arg.substring(1));
}
public static int getEvenDigits(int n){ // provide user arguments
return(recursiveGetEvenDigits(Integer.toString(n))); // set initial conditions
}
public static void main(String []args){
System.out.println(getEvenDigits(142));
}
}
prints 2
here is a quick pseudo code
function sumEven(int num){
if(num==0)
return 0;
int var =num%10;
if(var % 2)
return var+(num/10)
else
return 0+(num/10)
}

I do not understand the logic behind this prime number checker (Java)

I do not understand the logic behind this number checker and I'm wondering if somebody could help me understand it a little bit better.
Here's the code:
I will do my best to comment on what's happening but I do not fully understand it.
//find prime numbers between 2 and 100
class PrimeNumberFinder {
public static void main(String args[]) {
int i, j; // declare the integer variables "i" and "j"
boolean isPrime; // declare the Boolean variable is prime but do not assign value
// create a for loop that starts at two and stops at 99.
for (i=2; i < 100 ; i++) {
isPrime = true; // I do not know why isPrime is set to true here.
// This is where I get confused badly.. we give the "j" variable a value of two and check to see if it's less than whatever "i" divided by "j" is.
// If "i=2" then how would j (which is = 2) be less than or equal to i/j (2/2)?
for (j = 2; j <= i/j; j++)
if ((i%j) == 0) isPrime = false; // If a certain number goes in evenly that isn't 1, or "i" itself, it isn't prime so we set the boolean to false
if (isPrime) // if true print i
System.out.println(i + " Is a prime number");
}
}
}
As you can see the second for loop and almost everything going on within it confuses me, especially the "j <= i/j" because to me j is always going to be bigger.. and why is "j" even increasing? Can't you just divide it by two and determine whether or not it's prime that way?
Any help is greatly appreciated, thank you for reading.
Let's go through it line by line.
int i, j;
boolean isPrime;
We start with declaring our variables. Nothing too fancy.
for (i=2; i < 100; i++) {
isPrime = true;
Here we enter our loop that basically contains all the number we are going to check (here: 2 - 99). We also state that the current number is a prime number (unless proven otherwise).
for (j = 2; j <= i/j; j++)
if ((i%j) == 0) isPrime = false;
Now here is where the magic happens. We are going to check if we can divide the current number i evenly by any integer ranging from j == 2 to i/j (i/j ultimately is just a fancy way of writing Math.sqrt(i)). So why up until there?
Well, say we have two divisors a and b such that a * b = i. Now, if divisor a is bigger than the square root of i, then the other divisor b will be smaller than the square root of i. If not then a * b > i and this isn't possible.
So, if we can find a case in which we can divide evenly, this explicitly means that the current number is not prime and we set the isPrime variable to false.
if (isPrime) // if true print i
System.out.println(i + " Is a prime number");
}
So, if we still have isPrime == true, it means that the current number withstood our test and we can print it.
Two further improvements;
Once we know the number is not prime, there is no need to check any
additional divisors, so we want to exit the loop and hence a
break; statement could be addded.
2 is the only even prime number, so alternatively you could
start the second loop at j == 3 and increase by 2 after every execution.
You'll then have to consider the case when i == 2 separately.

Use Modulus Operator to Get Prime Numbers [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
How would you modify the below to print out all prime numbers from 1-100? The below has an issue with the number 2 coming back as not prime. The if(i%number == 0) condition is met for the number 2 as 2%2 is returned as 0.
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
for(int i=1; i<=100; i++){
if(isPrime(i)){
System.out.println(i + " is a prime number");
}else{
System.out.println(i + " is not a prime number");
}
}
}
public static boolean isPrime(int number){
for(int i=2; i<=number; i++){
if(i%number == 0){
return false;
}else{
return true;
}
}
return false;
}
}
i<=number
You shouldn't be checking whether the number is divisible by itself.
You also have another problem:
}else{
return true;
}
You're returning true as soon as you find a single non-divisible number, even if it does have factors later.
Here is an algorithm for determining whether or not a number is prime.
Is the number less than 2? If so, return false.
Is the number 2 or 3? If so, return true.
Is the number 4? If so, return false.
Take the square root of the number, rounded up to the next integer. This is optional for small prime numbers, but speeds up the determination for larger numbers.
Loop from 5 to the square root of the number (or the number), incrementing by 2.
Divide the loop number by the prime numbers determined so far.
If the modulus of the division is zero, return false.
If the loop is completed, return true.
You've got a couple issues here. Firstly, when checking whether or not a number is prime, never check every number up to the actual number being checked for primality. A check of all primes up to the square root of the number will always be sufficient.
To fix that error look at your for loop condition and edit it accordingly:
for(int i=2; i<=number; i++)
Secondly, when a function returns it stops. Currently with your if/else statement:
if (i%number == 0) {
return false;
} else {
return true;
}
If this condition goes to the else statement even once it will return true, you want to make sure you only actually return true when you've checked all of the numbers you intend to.
Additionally I don't think you've carefully considered what you base case is. What you are saying with your last line is that if everything previously slipped through the cracks then it should assume the number isn't prime. Think about it and I'm sure you'll be able to figure it out.
This will work. 2 is a special case when testing for primes. If you start to search a larger and larger...you might want to look at the sieve of eratosphenes.
Every prime number is a multiple of another number. Take 3 for example. Using the sieve, if you find 3 to be prime it will then 'ignore' all multiples of 3 thus reducing the amount of time taken to find consequent primes. It speeds things up...ALOT :)
public class JavaApplication47 {
public static void main(String[] args) {
for(int i=1; i<=100; i++){
if(isPrime(i)){
System.out.println(i + " is a prime number");
}else{
// System.out.println(i + " is not a prime number");
}
}
}
public static boolean isPrime(int n) {
for(int i=2; 2*i<n; i++) {
if(n%i==0)
return false;
}
return true;
}
}
SIEVE EXAMPLE - NOT IMPLEMENTED - Can be used for reference and understanding.
static boolean [] allPrimes = new boolean[10000];
public static void fillTheSieve(){
Arrays.fill(allPrimes, true);
allPrimes[0] = allPrimes[1] = false; //1 and 0 are false. winning
for (int i = 2; i < allPrimes.length; i++) {
//check if prime, if so getmultiples and declae false
if(allPrimes[i]){
for (int j = 2; i*j<allPrimes.length; j++) {
allPrimes[i*j] = false;
}
}
}
}
The definition of a prime number specifically states that one cannot be a prime number.
That means that isPrime(1) should return false. Which your implementation does.
But isPrime(2) should return true. Which your implementation does not. It does not because (2 % 2 == 0) and you are checking all numbers from 2 to N, not from 2 to N-1. The last number, N, will always yield a zero remainder (N % N == 0)
Just a few things to think about when dealing with Primes. You can have a special case for 2 at the start (i.e. something like if(number == 2)...).
In addition to your error in checking all the way to i<=number consider only how far you need to go in order to be certain it is not prime, hints have already been given with i*i or Math.sqrt
Another thing in the increment i++ think about what that entails, I realize this is only for the first 100 primes but you should always be thinking about performance. Do you really have to check all numbers (2,3,4,5,6...) (hint: if you have checked if its divisible by 2 then you dont need to check for 4,6,8 etc..)
Finally with your return statements, consider using a boolean flag that you set to false/true only when you are positive the number is a prime or is not. And you only need to use 1 return statement.
Hope that helps.
Please try this
public static boolean isPrime(int number) {
for(int i = 2; i * i <= number; i++) {
if (i % number == 0) {
return false;
} else {
return true;
}
}
return true;
}

Nested "FOR-loops" not working

I am doing an excercise in the book "Java how to program". The excercise wants me to write a method that determines if a number is "prime". (A "Prime number" is a positiv integer which is only dividable with itself and 1). Then I am supposed to implement the method in an application that displays all integers up to 10 000.
I use "double-values" to test whether the remainder is 0 or not, to test dividability.
Anyway, I just don´t get the program to work, it displays all numbers fro 3, with an increement on how many times each number is displayed (3 44 555 etc). Can anyone please tell me what I´m doing wrong?
The code is the following:
public class Oppgave625
{
public static void main(String[] args)
{
for(double a = 2; a <= 10000; a++)
{
for(double b = 1; b < a; b++)
{
if (prime(a, b) !=0)
{
System.out.printf("%.0f ", prime(a, b));
}
}
}
}
static double prime(double x, double y)
{
if (x % y != 0)
{
return x;
}
else
{
return 0;
}
}
}
Use int instead. double is not good for this purpose
you might want to read this article to understand the use of the % Operator for floating point numbers.
Actually, there were many individual errors in here. I shortened the prime() function to the point where it was only a modulo op, so I was able to inline it. Second, I inverted the test so it checked for numbers that do not have a remainder, and continues to the next number as soon as it finds a divisor. Third, I changed b = 1 so that we do not check for numbers divisible by 1, because this would result to all numbers. Finally, I only print out the numbers for which we do not discover a divisor. The final result:
public static void main(String[] args) {
outer:
for (int a = 2; a <= 1000; a++) {
for (int b = 2; b < a; b++) {
if (a % b == 0) {
continue outer;
}
}
System.out.println(a);
}
}
Edit: I forgot to mention, I also changed the types from floats to ints, since I'm sure that's what you meant.
It's great that you posted sample code for this, but there are several things that are wrong:
you should not use a floating point type for this, but an int or a long. Floating point types should never be used for precise values.
you are making two calls to your prime function, effectively doubling the required steps
your prime function only tells you whether two numbers divide themselves evenly, it does not tell you whether one is a prime or not
for prime numbers, you should use a more efficient algorithm instead of calculating the same values over and over for each number. Look up Sieve of Eratosthenes.
You are approaching the problem like this: The number A is NOT prime, whenever i can find a number B that can divide A without a remainder.
Bur right now, you print out A whenever it is not dividable by B.
Instead you could say: whenever A not divisible by B, increase B. When i found a B to divide A, quit the inner loop, print nothing.
When i found no B, print A and quit loop.
Furthermore, you only have to test for divisibility of A until (a/2)-1.
A prime number is a number that is only divisible by one and itself. That is: one number. Your code is comparing two numbers as in the Euclidean algorithm for testing coprime-ness. This is very different than testing if a number is prime.
Your code should look something like this:
for i = 2 to 10,000 {
if( isPrime(i) ){
print i
}
}
function isPrime( int n ){
for i = 2 to n {
next if i == n
if( n % i == 0 ){
return 0;
}
}
return 1;
}
boolean isPrime = true;
for (int i = 2; i<=100; i++){
for(int j = 2; j<=i/2; j++){
isPrime = true;
if (i%j==0){
isPrime = false;
break;
}
}
if (isPrime){
Log.d("PrimeNumber",""+i);
}
}

Categories