I'm trying to count the digits of an integer with java, it supposed to give 4 but instead I get 1 .
I don't know if I did something wrong, if someone could help.
Here's the code :
public static void main(String[] args) {
int n = 4781, i = 0;
while (n != 0) {
n %= 10;
n /= 10;
i++;
}
System.out.println(i);
}
The n %= 10 is unnecessary and in fact the source of the problem here. If you remove it, the code will work.
Usually when you do these kinds of "do something for each digit" you use % 10 to find the current digit a little bit like this:
int digit = n % 10;
System.out.println("The current digit is " + digit);
But in your case you don't actually care what the digits are, you only care how many there are, so there's no need to do % 10 at all.
And the way you did it you overwrote n (which is supposed to hold the current state of the number) with the current digit and then divided by 10. So no matter what the first digit is, this will never return a number bigger than 1.
Related
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;
}
Hello everyone I was having some issue splitting up a user input number using printf (I do have to use printf). My problem is that when I put in say the number 12345 it will print the integers on five separate lines, and also has them in the reverse order. So it would look something like this when I put in the integer 12345:
5
4
3
2
1
But without the spaces (I need those as well). I want it to print like this: 1 2 3 4 5.
Here is the code I have so far:
public static void main(String[]args){
Scanner input = new Scanner(System.in);
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
while (one > 0){
System.out.printf("%d%n", one % 10);
one = one /10;
}
}
First, in order to avoid printing on separate lines, you should avoid using the %n formatting character in your printf().
Now, how do you print the digits in the correct order? Well, since you are limited to five-digit numbers, you can do something like this:
for ( int divisor = 10000; divisor >= 1; divisor /= 10 ) {
System.out.printf( "%d ", n / divisor);
n %= divisor;
}
System.out.printf( "%n" ); // Just to complete the line
(divisor /= 10 is shortcut for divisor = divisor / 10, and n %= divisor is shortcut for n = n % divisor).
So you start by dividing the number by 10000. This will give you the fifth digit from the right. Then you take the remainder and put it in n. This gives you just the remaining four digits. Then the loop will reduce your divisor to 1000, which will take the fourth digit from the right, and you keep doing that until you reach a divisor of 1.
Another approach that does not require knowing that the number is 5 digits long, but requires recursion is to write a method like so:
public static void printSplitNumber( int n ) {
if ( n == 0 ) {
return;
}
printSplitNumber( n / 10 );
System.out.printf( "%d ", n % 10);
}
And from your main, call:
printSplitNumber(n);
System.out.printf("%n"); // Again, just completing the line.
This recursive method relies on the fact that you print the current digit only after all the rest of the number has been printed. So this causes it to print it to the right of the rest of the digits, giving you the effect you need.
Unless the assignment is to figure out how to split the digits numerically, I think that the simplest approach is to either use Scanner's nextLine() method to get a String, or convert your int to a String, and then split the characters of the String.
substring() is a little heavy - a lighter-weight way to do it is by inspecting character positions, like this:
public void printDigits(String chars) {
for(int i = 0; i < chars.length(); i++) {
System.out.printf("%c ", chars.charAt(i));
}
}
This approach uses the substring method as opposed to mathematically manipulating the int value.
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
String x = Integer.toString(one);
for(int i = 0; i < x.length() - 1; i++)
{
// On last digit in number
if(i + 1 == x.length())
{
System.out.printf("%s ", x.substring(x.length()));
}
else
{
System.out.printf("%s ", x.substring(i, i + 1));
}
}
Simplified printf statemnts thanks to #Jerry101's comment
I'd like to create a program wherein a user will type a number and the program will tell if it is divisible by 3 or not. But %, /, +, * can't be used in the program. Anybody here got some ideas how to do that?
public static void main(String[] args) {
String number = "123456";
int sum = 0;
for (char c : number.toCharArray()) {
sum = sum - (0 - c) - '0';
while (sum >= 3) {
sum -= 3;
}
}
System.out.print("divisible by 3? ");
System.out.println(sum == 0);
}
Alternatively you can keep subtracting 3 until your number is either 0 (divisible by 3) or <0: not divisible by 3.
ps: it needs to be adapted if you want to deal with negative numbers
easy peasy...
boolean divisibleBy3(int n) {
return (""+n).matches("([0369]|[147]([0369]|[147][0369]*[258])*([" +
"258]|[147][0369]*[147])|[258]([0369]|[258]" +
"[0369]*[147])*([147]|[258][0369]*[258]))*");
}
A number is divisible by there if the sum of all the digits is also divisible by 3. You can iterate the process until you have a number smaller than 10 and compare it which known divisors (3,6 and 9)
Since it is most likely a game or homework and you can use + you can simple use minus two times: a - - b is equivalent to a + b
Assuming you can use the - operator then
bool divBy3(int n)
{
while (n >= 0)
{
n -= 3;
}
return n == 0;
}
This will return true if n is exactly divisible by 3, false otherwise. Note that this is really inefficient! Using the % operator would be far better.
Divisibility by 3 in binary representation is like divisibility by 11 in decimal (10+1): sum of digits in even places minus sum of digits on odd places is in turn divisible by 3 (maybe 0).
How can I use a “for” loop to find the first 3 perfect numbers after 28?
Here is some code I'm using.
I can't seem to get anything past 2 numbers. If I try to increase i<= 2000000000 it tells me the integer is to large.
public class JBaneling
{
public static void main(String args[])
{
System.out.println("3 nearest Perfect numbers after 29 ");
for (int i = 29; i <= 2000000000; i++) {
test1(i);
}
}
public static void test1(int number)
{
int sum = 0;
for(int divisor=1; divisor < number; divisor++)
{
if ((number % divisor) ==0)
{
sum = sum + divisor;
}
}
if(sum==number)
{
System.out.println(number + " is a perfect number");
}
}
}
It's just taking a long time to compute the third perfect number. After 8128 the next perfect number is 33550336. Now consider that your code is testing every integer between 8128 ... 33550336, by computing each divisor of each of those integers.
Also consider that this next perfect number, 33550336 is the largest perfect number that you'll be able to represent with a java int: Integer.MAX_VALUE is (2^31 - 1). You'll get a few more with a long - Long.MAX_VALUE is (2^63 - 1) - but you'll be waiting a long time for that 8th perfect number.
Note that you only need to consider divisors up to the square root of number, then find their matching divisor above the square root, but even so you'll still need to wait a really long time before getting to the next perfect number.
Are you sure the code actually terminated? I don't see anything wrong with the actual calculations, but it is hideously inefficient, so if you are getting only 2 numbers, that's probably because you stopped the program before it ever got to the third number. In case you were wondering, it is 33550336, which is well under the loop limit you set.
I have run into a weird issue for problem 3 of Project Euler. The program works for other numbers that are small, like 13195, but it throws this error when I try to crunch a big number like 600851475143:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at euler3.Euler3.main(Euler3.java:16)
Here's my code:
//Number whose prime factors will be determined
long num = 600851475143L;
//Declaration of variables
ArrayList factorsList = new ArrayList();
ArrayList primeFactorsList = new ArrayList();
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
//If the integer(s) in the factorsList are divisable by any number between 1
//and the integer itself (non-inclusive), it gets replaced by a zero
for (int i = 0; i < factorsList.size(); i++)
{
for (int j = 2; j < (Integer) factorsList.get(i); j++)
{
if ((Integer) factorsList.get(i) % j == 0)
{
factorsList.set(i, 0);
}
}
}
//Transfers all non-zero numbers into a new list called primeFactorsList
for (int i = 0; i < factorsList.size(); i++)
{
if ((Integer) factorsList.get(i) != 0)
{
primeFactorsList.add(factorsList.get(i));
}
}
Why is it only big numbers that cause this error?
Your code is just using Integer, which is a 32-bit type with a maximum value of 2147483647. It's unsurprising that it's failing when used for numbers much bigger than that. Note that your initial loop uses int as the loop variable, so would actually loop forever if it didn't throw an exception. The value of i will go from the 2147483647 to -2147483648 and continue.
Use BigInteger to handle arbitrarily large values, or Long if you're happy with a limited range but a larger one. (The maximum value of long / Long is 9223372036854775807L.)
However, I doubt that this is really the approach that's expected... it's going to take a long time for big numbers like that.
Not sure if it's the case as I don't know which line is which - but I notice your first loop uses an int.
//Generates a list of factors
for (int i = 2; i < num; i++)
{
if (num % i == 0)
{
factorsList.add(i);
}
}
As num is a long, its possible that num > Integer.MAX_INT and your loop is wrapping around to negative at MAX_INT then looping until 0, giving you a num % 0 operation.
Why does your solution not work?
Well numbers are discrete in hardware. Discrete means thy have a min and max values. Java uses two's complement, to store negative values, so 2147483647+1 == -2147483648. This is because for type int, max value is 2147483647. And doing this is called overflow.
It seems as if you have an overflow bug. Iterable value i first becomes negative, and eventually 0, thus you get java.lang.ArithmeticException: / by zero. If your computer can loop 10 million statements a second, this would take 1h 10min to reproduce, so I leave it as assumption an not a proof.
This is also reason trivially simple statements like a+b can produce bugs.
How to fix it?
package margusmartseppcode.From_1_to_9;
public class Problem_3 {
static long lpf(long nr) {
long max = 0;
for (long i = 2; i <= nr / i; i++)
while (nr % i == 0) {
max = i;
nr = nr / i;
}
return nr > 1 ? nr : max;
}
public static void main(String[] args) {
System.out.println(lpf(600851475143L));
}
}
You might think: "So how does this work?"
Well my tough process went like:
(Dynamical programming approach) If i had list of primes x {2,3,5,7,11,13,17, ...} up to value xi > nr / 2, then finding largest prime factor is trivial:
I start from the largest prime, and start testing if devision reminder with my number is zero, if it is, then that is the answer.
If after looping all the elements, I did not find my answer, my number must be a prime itself.
(Brute force, with filters) I assumed, that
my numbers largest prime factor is small (under 10 million).
if my numbers is a multiple of some number, then I can reduce loop size by that multiple.
I used the second approach here.
Note however, that if my number would be just little off and one of {600851475013, 600851475053, 600851475067, 600851475149, 600851475151}, then my approach assumptions would fail and program would take ridiculously long time to run. If computer could execute 10m statements per second it would take 6.954 days, to find the right answer.
In your brute force approach, just generating a list of factors would take longer - assuming you do not run out of memory before.
Is there a better way?
Sure, in Mathematica you could write it as:
P3[x_] := FactorInteger[x][[-1, 1]]
P3[600851475143]
or just FactorInteger[600851475143], and lookup the largest value.
This works because in Mathematica you have arbitrary size integers. Java also has arbitrary size integer class called BigInteger.
Apart from the BigInteger problem mentioned by Jon Skeet, note the following:
you only need to test factors up to sqrt(num)
each time you find a factor, divide num by that factor, and then test that factor again
there's really no need to use a collection to store the primes in advance
My solution (which was originally written in Perl) would look something like this in Java:
long n = 600851475143L; // the original input
long s = (long)Math.sqrt(n); // no need to test numbers larger than this
long f = 2; // the smallest factor to test
do {
if (n % f == 0) { // check we have a factor
n /= f; // this is our new number to test
s = (long)Math.sqrt(n); // and our range is smaller again
} else { // find next possible divisor
f = (f == 2) ? 3 : f + 2;
}
} while (f < s); // required result is in "n"