Total noob question, but I am in my first Java class and working though a problem set. I know how to see if a number is in a specific range (posted below) but I am trying to find if this holds true of any of the nearest hundreds.
The rules are N has to be within 10 of either side of nearest 100.
if (n >= 90 && n <= 110) {
return true;
} else {
return false;
}
You can use % operator to calculate remainder of division.
int r = Math.abs(n) % 100; // use abs(), or r will be negative if n is negative
return r <= 10 || 90 <= r;
Related
I understood the logic behind the problem's solution, but in the coded solution I am a bit confused about the return statement in the end. Please explain to me what is its significance, why is it being used, etc ? (not why return is used but why is that value being returned).
class Solution {
public boolean isPalindrome(int x) {
// 2 cases x < 0 = false case
// x > 0 = test case
if (x < 0 || x % 10 == 0 && x != 0){
return false;
}
else {
int newNum = 0;
while (x > newNum){
int r = (x % 10);
newNum = newNum * 10 + r;
x /= 10;
}
//the part I am confused about - below
return x == newNum || x == newNum / 10;
}
}
}
So to understand the Logic for the return statement let us take 2 numbers
1234321
678876
So one thing here While loop is doing is to create a new number(newNum) out of X and making sure that newNum stores the reverse of X till the middle point.
So in case of 1234321 , this while loop will execute till X=123 and newNum=1234.
After exiting out from while loop with these values, out of the 2 statements in return, x == newNum / 10 will give true result hence return statement will return true.which means the number is palindrome.
Please note here that the no. digits in given integer is odd(7)
Let us now Take other example 678876
In this case when the while loop ends, the value for the X would be 678 and newNum would be 678
out of the 2 statements in return, x == newNum this time will give true result hence return statement will return true again .which means the number is palindrome.
Please note here that the no. digits in given integer is even(6)
All in all, this statement return x == newNum || x == newNum / 10;
is to make sure that we are covering the condition for both Odd and even no. of digits in the given integer X.
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;
}
I'm trying to implement a method which checks any integer and returns true if it's prime using Fermat's primality test.
I divided the problem depending on whether the input is less than 40 or not. If the input is less than 40 then I apply the test for every integer up until n-1. Else, if the integer is greater than 40 then the test is applied for every integer up until 40. However, it fails for some primes.
public static boolean isPrime (double n){
int counter=0;
boolean isPrime=false;
if(n<40) {
for (int a = 2; a < n - 1; a++) {
if (Math.pow(a, n - 1) % n == 1) counter++;
}
if (counter == n - 3) isPrime = true;
}
else {
for (int a = 2; a <= 40; a++) {
if (Math.pow(a, n - 1) % n == 1) counter++;
}
if (counter == 39) isPrime = true;
}
return isPrime;
}
Is it a logical issue or something else?
Math.pow works on doubles and the result is only approximate. Modulo on the other hand works on ints which have a range up to a little over 2 billion, is your pow producing some numbers larger than that by any chance? (17^18 seems to be a sure bet for 19...)
So how to fix this:
you can implement your own pow(a,b,n) (power modulo n) using multiplication and modulo on integers. That should work correctly. Make a function to raise a to power b using a series of multiplications, apply %n to the intermediate result after each step...
Problem: check if a number is a power of 4.
my solution in java:
public static boolean isPowerOfFour(int num) {
return (Math.log(num) % Math.log(4) == 0);
}
But it seems off in some cases, for example when num is 64.
I found out that if I change the code a little bit, it works well.
public static boolean isPowerOfFour(int num) {
return (Math.log(num) / Math.log(4) %1 == 0);
}
I think both solutions do the same thing, check if the remaining of logNum/logBase is 0. But why the first solution doesn't work? Is it because the solution is incorrect or relative to some low level JVM stuff?
Thanks.
Building on #dasblinkenlight's answer, you can easily combine both conditions (first, a power of 2, then any power of 4 among all possible powers of 2) with a simple mask:
public static boolean isPowerOfFour(int num) {
return ((( num & ( num - 1 )) == 0 ) // check whether num is a power of 2
&& (( num & 0xaaaaaaaa ) == 0 )); // make sure it's an even power of 2
}
No loop, no conversion to float.
Checking if a number is a power of 4 is the same as checking that the number is an even power of 2.
You can check that a number x is a power of two by verifying that x & (x-1) is zero (here is the explanation of how this works)
If your number is not a power of 2, return false. Otherwise, shift the number right until you get to one, and count the number of shifts. If you shifted an odd number of times, return false; otherwise, return true:
public static boolean isPowerOfFour(int num) {
if ((num & (num-1)) != 0) {
return false;
}
int count = 0;
while (num != 1) {
num >>= 1;
count++;
}
return count % 2 == 0;
}
Demo.
Functions like Math.log return floating point numbers with a rounding error. So when num = 64 for example, Math.log (num) / Math.log (4) is not exactly 3, but a number close to 3.
public static boolean isPowerOfFour(int num) {
if (num > 0) {
while (num % 4 == 0) num /= 4;
}
return (num == 1);
}
This solution can be quite easily adapted to check whether num is a power of some other integer greater than 1.
The reason it doesn't work is because Math.log() returns a double. The answer of false is reflective of rounding errors; log(64) base e is an irrational number but Java needs to truncate it to fit it's width.
What am doing wrong here in this piece of code ? What is a better way to generate N digit random number ?
public static boolean isPrime(long n) {
if (n <= 3) {
return n > 1;
} else if (n % 2 == 0 || n % 3 == 0) {
return false;
} else {
for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return false;
}
}
return true;
}
}
public static long getPrime(int digit){
long sample;
long multiple = Math.round(Math.pow(10, digit));
do{
sample = Math.round(Math.random()* multiple);
//System.out.println(sample);
}while(!isPrime(sample));
return sample;
}
What am doing wrong here in this piece of code:
Lots of things.
Your test for primality is mathematically bogus as noted by the commenters.
You have implemented the test incorrectly. The Math.pow(...) function returns an double, so you are liable suffer from loss of precision. But you need full precision for the remainder operation (%) to give you the correct answer.
You are ignoring the perfectly serviceable prime number generation and primality test methods that are provided by the standard BigInteger class; see the javadoc for details.
My guess is that point #2 is what you are missing.
Your getPrime() method is nearly right for 5 < N < 19. It won't work for N = 19 because the largest possible long value is 9223372036854775807 which is 19 digits long. The reason it doesn't quite work for values lower than 19 is that it can produce numbers with fewer than the required number of digits. You need while(sample < (long) Math.pow(10, digit - 1) || !isPrime(sample))
Now that you have updated your isPrime() method, it almost works, but you need to replace
for (int i = 5; i * i <= n; i += 6)
by
for (long i = 5; i * i <= n; i += 6)
because otherwise the value of i * i can overflow.
Math.random() has only 15-16 digits of precision so won't produce all 16, 17, 18, 19 or 20 digit numbers. The problem is that the 16, 17, 18, 19, 20 digits are far more likely to be multiples of 2, 4, 8, 16 and 32 respectably and thus not prime.
I suggest you use SecureRandom.nextLong() taking the lower N digits.