Implement fibonacci using recursion without using java.bignumber - java

I am trying to implement the Fibonacci sequence without using the BigInteger Class import, hence I rewrite my own add method, and I spent two days on it, But I don't know why the answer of the first 6 numbers is correct and the rest of the answers are the reverse of the correct one(eg. n = 7, my answer: 31 the correct one: 13; n = 15, my answer = 016, correct one= 610), and when n becomes greater, the answer gets totally wrong(not even the reversed of the correct one. This happened when n >= 25).
Any advice would be appreciated!
The following is my output:
The 0th Fibonacci number is :
0
The 1th Fibonacci number is :
1
The 2th Fibonacci number is :
1
The 3th Fibonacci number is :
2
The 4th Fibonacci number is :
3
The 5th Fibonacci number is :
5
The 6th Fibonacci number is :
8
The 7th Fibonacci number is :
31
The 8th Fibonacci number is :
12
The 9th Fibonacci number is :
43
The 10th Fibonacci number is :
55
The 11th Fibonacci number is :
98
The 12th Fibonacci number is :
441
The 13th Fibonacci number is :
332
The 14th Fibonacci number is :
773
The 15th Fibonacci number is :
016
The 16th Fibonacci number is :
789
The 17th Fibonacci number is :
7951
The 18th Fibonacci number is :
4852
The 19th Fibonacci number is :
1814
The 20th Fibonacci number is :
5676
The 21th Fibonacci number is :
64901
The 22th Fibonacci number is :
11771
The 23th Fibonacci number is :
75682
The 24th Fibonacci number is :
86364
The 25th Fibonacci number is :
52047
The 26th Fibonacci number is :
393021
The 27th Fibonacci number is :
814491
The 28th Fibonacci number is :
118413
The 29th Fibonacci number is :
922905
The 30th Fibonacci number is :
040428
And the following is my code:
package com.example.helloworld;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Fibonacci_Recursive{
public static void main(String[] args) {
long start = System.nanoTime();
long time = 0L;
for(int i = 0; time <= 60L; i++)
{
Fibonacci_Recursive fr = new Fibonacci_Recursive(i);
time = ((System.nanoTime() - start) / 1000_000_000);
}
}
private Fibonacci_Recursive(int n){
System.out.println("The " + n + "th Fibonacci number is :");
if (n <= 1){
System.out.println(n);
}
else {
int[] finalResult = getF(n);
String st = "";
for (int i = 0; i < finalResult.length; i++){
st = finalResult[i] + st;
}
System.out.println(st);
}
}
private int[] getF(int n){
int[] head = new int[1];
if (n <= 1) {
head[0] = n;
return head;
}
return add(getF(n - 1), getF(n - 2));
}
private int[] add(int[] s1, int[] s2){
int carrier = 0;
ArrayList<Integer> result = new ArrayList<>();
int[] array1 = s1;
int[] array2 = s2;
array1 = reverseGeneralArray(array1);
array2 = reverseGeneralArray(array2);
int min = array2.length;
int min2 = array1.length;
if(min2 > min) {
for (int i = 0; i < min; i++) {
int x = array1[i] + array2[i];
result.add((x + carrier) % 10);
carrier = x / 10;
}
for (int j = 0; j <= min2 - min - 1; j++) {
int index = min;
result.add((array1[index] + carrier) % 10);
carrier = (array1[index] + carrier) / 10;
index++;
}
if (carrier > 0) {
result.add(carrier);
}
Collections.reverse(result);
return convertIntegers(result);
}
else if(min2 < min)
{
for(int i = 0; i < min2; i ++){
int x = array1[i] + array2[i];
result.add((x + carrier) % 10);
carrier = x / 10;
}
for(int j = 0; j <= min - min2 - 1; j++){
int index = min2;
result.add((array2[index] + carrier) % 10);
carrier = (array2[index] + carrier) / 10;
index++;
}
if (carrier > 0) {
result.add(carrier);
}
Collections.reverse(result);
return convertIntegers(result);
}else {
for (int i = 0; i < min; i++) {
int x = array1[i] + array2[i];
result.add((x + carrier) % 10);
carrier = x / 10;
}
if (carrier > 0) {
result.add(carrier);
}
Collections.reverse(result);
return convertIntegers(result);
}
}
private static int[] convertIntegers(ArrayList<Integer> integers)
{
int[] ret = new int[integers.size()];
for (int i=0; i < integers.size(); i++)
{
ret[i] = integers.get(i);
}
return ret;
}
private int[] reverseGeneralArray(int[] x){
int[] newX = new int[x.length];
for(int i = 0; i < x.length; i++){
newX[i] = x[x.length - i -1];
}
return newX;
}
}

You miss building the result, you concatenate wrong (reverse) way String st from the int[] finalResult:
private Fibonacci_Recursive(int n) {
...
for (int i = 0; i < finalResult.length; i++) {
//Replaced st = finalResult[i] + st by
st = st + finalResult[i];
}
...
}
Extra: Consider, when concatenating strings in a loop, since concatenation copies the whole string, to use StringBuilder:
StringBuilder st = new StringBuilder();
for (int i = 0; i < finalResult.length; i++) {
st.append(finalResult[i]);
}
Update: Starting from 25, an error becomes evident: the carrier is not right when the sum of two digits is equal to 10 (74025 instead of 75025). The bug is at the add method,where the carrier should be calculated as:
carrier = (x + carrier) / 10;
i.e.: you have to take into account previous carrier.

Related

To find out Armstrong number in between numbers

Below is my code.
package com.ofss.java.examples;
import java.util.Scanner;
class ArmstrongNumber {
public static void main(String[] args) {
int c = 0, a;
int n1, n2;//Range in which armstrong number need to find
Scanner s = new Scanner(System.in);
System.out.println("Enter the first number");
n1 = s.nextInt();
System.out.println("Enter the second number");
n2 = s.nextInt();
for (int i = n1; i <= n2; ++i) {
while (i > 0) {
a = i % 10;
System.out.println(a);
i = i / 10;
System.out.println(i);
c = c + (a * a * a);
System.out.println(c);
}
if (i == c)
System.out.println(c + "armstrong number");
else
System.out.println(c + "Not armstrong number");
}
}
}
I am getting incorrect results after executing. Code runs for infinite number till you stops it. It must print number between 151-154 (153 as armstrong).
Also, it is incorrectly printing 153 as not Armstrong number.
Armstrong Number
...is a number that is the sum of its own digits each raised to the power of the number of digits.
You should not change i since this is also used in
for (int i = n1; i <= n2; ++i)
Or you will probably never exit that loop eiter since you expect i to be negative at the end of the first iteration. Hard to increment until it reach n2.
Use a different variable to keep track of i safely.
int j = i;
while(j > 0) ...
About Armstrong number:
Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits
You need to put each digit to the power of the length of the number (the number of digit).
153 = 1^3 + 5^3 + 3^3
1634 = 1^4 + 6^4 + 3^4 + 4^4
Here is the method for it :
public static boolean isArmstrongNumber(int number){
int power = Integer.toString(number).length(); //just to get the number of digit...
int tmp = number;
int digit , sum = 0;
while(tmp > 0){
digit = tmp % 10;
sum += Math.round(Math.pow(digit , power));
tmp /= 10;
}
return sum == number;
}
Using this check from 0 to 10.000 gives :
0
1
2
3
4
5
6
7
8
9
153
370
371
407
1634
8208
9474
Same as Wikipedia :
The sequence of base 10 narcissistic numbers starts: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, ...
Note that using a method remove the risk of forgetting to reset your variable like c in your case. Correcting this would give you a few more "correct" results (well the one with 3 digits)
You can also use less mathematics to read the number and use char[], remember that you need to substract '0' value to get the numeric value for a character :
public static boolean isArmstrongNumber(int number){
char[] digits = Integer.toString(number).toCharArray();
int power = digits.length;
int sum = 0;
for(char c : digits){
int digit = c - '0';
sum += Math.round(Math.pow(digit, power));
}
return sum == number;
}
There are two things.
you are updating i everytime as you have used it in while, so use different variable than i for this calculation.
int num = i;
c is used to compare sum of cube is same as number but you are not resetting it once the one iteration is over. so make c=0 inside for loop.
c = 0;
Also while printing you are using c, there should be i which is correct and real number.
Below is the working code you may try.
public static void main(String[] args)
{
int c = 0, a;
int n1, n2;//Range in which armstrong number need to find
Scanner s = new Scanner(System.in);
System.out.println("Enter the first number");
n1 = s.nextInt();
System.out.println("Enter the second number");
n2 = s.nextInt();
for (int i = n1; i <= n2; ++i)
{
int num = i;
while (num > 0)
{
a = num % 10;
num = num / 10;
c = c + (a * a * a);
}
if (i == c)
System.out.println(i + "armstrong number");
else
System.out.println(i + "Not armstrong number");
c = 0;
}
}
public class ArmstrongNumber {
private final int n1, n2;
public ArmstrongNumber(int n1, int n2) {
this.n1 = n1;
this.n2 = n2;
}
protected static boolean isArmstrong(int n) {
if(n < 0)
return false;
int remaining=n;
int sumCube=0;
while (remaining>0) {
int d = remaining % 10;
sumCube += cube(d);
remaining /= 10;
}
return n == sumCube;
}
private static int cube(int d) {
return d*d*d;
}
public Integer[] find() {
List<Integer> results = new ArrayList<>();
for (int i = n1; i <= n2; ++i)
{
if (isArmstrong(i))
results.add(i);
}
return results.toArray(new Integer[0]);
}
}
There are lot of things to improve in your code. One of the working logics as below:
for (int i = n1; i <= n2; ++i) {
int sum = 0, remainder = 0, digits = 0, temp = 0;
temp = i;
while (temp != 0) {
digits++;
temp = temp / 10;
}
temp = i;
while (temp != 0) {
remainder = temp % 10;
sum = sum + (int) Math.pow(remainder, digits);
temp = temp / 10;
}
if (i == sum)
System.out.println(i + " is an Armstrong number.");
else
System.out.println(i + " isn't an Armstrong number.");
}

Adding integers in Range not working for negative numbers

I am trying to do this exercise:
Write a program that asks the user for N and M and adds up the
integers between N and M using the formula
SUM(N to M) = SUM( 1 to M ) - SUM( 1 to N-1 )
I can get this to work for positive numbers but not negative numbers.
static int method2(int n, int m) {
int sum = 0;
int sum2 = 0;
for (int i = 1; i <= m; i++) {
sum = sum + i;
}
for (int i = 1; i <= n - 1; i++) {
sum2 = sum2 + i;
}
System.out.println("sum: " + sum + ", sum2: " + sum2);
return sum = sum - sum2;
}
e.g.
using n = -1, m = 1 returns sum = 1.
Using n = -5, m = 5 returns sum = 15.
Using n = 5, m = -5 returns sum = -10.
These should all return 0.
e.g.
Using n = -2, m = 3, returns sum = 6.
Using n = -2, m = 4, returns sum = 10.
The problem is with for (int i = 1; i <= n - 1; i++), specifically i <= n - 1 because when n-1 <= 0 this will not run. I just can't think of a way around it.
Your formula
SUM(N to M) = SUM( 1 to M ) - SUM( 1 to N-1 )
Doesn't really make sense for negative values. If you give that up you can make your program simpler. We very often start for loops at 0 or 1 but that doesn't have to be the case. You could instead start your loop at a n which might be negative:
static int method2(int n, int m) {
int sum = 0;
for (int i = n; i <= m; i++) {
sum = sum + i;
}
System.out.println("sum: " + sum);
return sum;
}
You could always check before if n < 0.
And then do another reverse loop for negative numbers.
e.g.
int sum = 0;
if(m < 0){
for(int i = 0; i >= m; i--) {
sum += i;
}
} else {
for (int i = 1; i <= m; i++) {
sum += i;
}
}
If you really have to use that formula you could use instead of:
for (int i = 1; i <= m; i++) {
the following code which changes the index either by 1 or by -1
for (int i = 1; i <= m; i+=(int)Math.signum(m-1+0.1)) {
(added 0.1 such that in case m is 1 the result is positive and not 0)
Ofc you should do the same for n.

Armstrong number logic error

Here I've code to print armstrong numbers until some particular range. But this programs doesnt prints all the numbers within the range. It just prints armstrong number within range of 1000. Whats wrong in this code?
public static void main(String[] args) {
long N, temp, sum = 0;
Scanner ip = new Scanner(System.in);
System.out.print("Enter the range: ");
N = ip.nextLong();
for (long i = 1; i < N; i++) {
temp = i;
while (temp > 0) {
long rem = temp % 10;
sum = sum + (rem * rem * rem);
temp = temp / 10;
}
if (sum == i) {
System.out.println(" " + i);
}
sum = 0;
}
ip.close();
}
when the input is 100000 it just prints
Enter the range: 100000
1
153
370
371
407
According to the definition of Armstrong numbers, each digit in the number is to be raised to n where is the number of digits in the number.
However your logic does not implement that. It only raises digits to the third power.
That's why your code fails.
Here you go, use this code:
for (long i = 1; i < N; i++) {
temp = i;
int n=Long.toString(i).length();
while (temp > 0) {
long rem = temp % 10;
sum = sum + (long) Math.pow(rem, n);
temp = temp / 10;
}
if (sum == i) {
System.out.println(" " + i);
}
sum = 0;
}
Ideone link here.

How do I generate Primes Using 6*k +- 1 rule

We know that all primes above 3 can be generated using:
6 * k + 1
6 * k - 1
However we all numbers generated from the above formulas are not prime.
For Example:
6 * 6 - 1 = 35 which is clearly divisible by 5.
To Eliminate such conditions, I used a Sieve Method and removing the numbers which are factors of the numbers generated from the above formula.
Using the facts:
A number is said to be prime if it has no prime factors.
As we can generate all the prime numbers using the above formulas.
If we can remove all the multiples of the above numbers we are left with only prime numbers.
To generate primes below 1000.
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2);//explicitly add
primes.add(3);//2 and 3
int n = 1000;
for (int i = 1; i <= (n / 6) ; i++) {
//get all the numbers which can be generated by the formula
int prod6k = 6 * i;
primes.add(prod6k - 1);
primes.add(prod6k + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
//remove all the factors of the numbers generated by the formula
for(int j = k * k; j <= n; j += k)//changed to k * k from 2 * k, Thanks to DTing
{
int index = primes.indexOf(j);
if(index != -1)
primes.remove(index);
}
}
System.out.println(primes);
However, this method does generate the prime numbers correctly. This runs in a much faster way as we need not check for all the numbers which we do check in a Sieve.
My question is that am I missing any edge case? This would be a lot better but I never saw someone using this. Am I doing something wrong?
Can this approach be much more optimized?
Taking a boolean[] instead of an ArrayList is much faster.
int n = 100000000;
boolean[] primes = new boolean[n + 1];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 1; i <= n / 6; i++) {
int prod6k = 6 * i;
primes[prod6k + 1] = true;
primes[prod6k - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
for (int i = 0; i <= n; i++)
if (primes[i])
System.out.print(i + " ");
5 is the first number generated by your criteria. Let's take a look at the numbers generated up to 25:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
Now, let's look at these same numbers, when we use the Sieve of Eratosthenes algorithm:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
After removing 2:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
After removing 3:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
This is the same as the first set! Notice they both include 25, which is not prime. If we think about it, this is an obvious result. Consider any group of 6 consecutive numbers:
6k - 3, 6k - 2, 6k - 1, 6k, 6k + 1, 6k + 2
If we factor a little, we get:
3*(2k - 1), 2*(3k - 1), 6k - 1, 6*(k), 6k + 1, 2*(3k + 1)
In any group of 6 consecutive numbers, three of them will be divisible by two, and two of them will be divisible by three. These are exactly the numbers we have removed so far! Therefore:
Your algorithm to only use 6k - 1 and 6k + 1 is exactly the same as the first two rounds of the Sieve of Erathosthenes.
It's a pretty nice speed improvement over the Sieve, too, because we don't have to add all those extra elements just to remove them. This explains why your algorithm works and why it doesn't miss any cases; because it's exactly the same as the Sieve.
Anyway, I agree that once you've generated primes, your boolean way is by far the fastest. I have set up a benchmark using your ArrayList way, your boolean[] way, and my own way using LinkedList and iterator.remove() (because removals are fast in a LinkedList. Here's the code for my test harness. Note that I run the test 12 times to ensure that the JVM is warmed up, and I print the size of the list and change the size of n to attempt to prevent too much branch prediction optimization. You can also get faster in all three methods by using += 6 in the initial seed, instead of prod6k:
import java.util.*;
public class PrimeGenerator {
public static List<Integer> generatePrimesArrayList(int n) {
List<Integer> primes = new ArrayList<>(getApproximateSize(n));
primes.add(2);// explicitly add
primes.add(3);// 2 and 3
for (int i = 6; i <= n; i+=6) {
// get all the numbers which can be generated by the formula
primes.add(i - 1);
primes.add(i + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
// remove all the factors of the numbers generated by the formula
for (int j = k * k; j <= n; j += k)// changed to k * k from 2 * k, Thanks
// to DTing
{
int index = primes.indexOf(j);
if (index != -1)
primes.remove(index);
}
}
return primes;
}
public static List<Integer> generatePrimesBoolean(int n) {
boolean[] primes = new boolean[n + 5];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 6; i <= n; i+=6) {
primes[i + 1] = true;
primes[i - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
int approximateSize = getApproximateSize(n);
List<Integer> primesList = new ArrayList<>(approximateSize);
for (int i = 0; i <= n; i++)
if (primes[i])
primesList.add(i);
return primesList;
}
private static int getApproximateSize(int n) {
// Prime Number Theorem. Round up
int approximateSize = (int) Math.ceil(((double) n) / (Math.log(n)));
return approximateSize;
}
public static List<Integer> generatePrimesLinkedList(int n) {
List<Integer> primes = new LinkedList<>();
primes.add(2);// explicitly add
primes.add(3);// 2 and 3
for (int i = 6; i <= n; i+=6) {
// get all the numbers which can be generated by the formula
primes.add(i - 1);
primes.add(i + 1);
}
for (int i = 0; i < primes.size(); i++) {
int k = primes.get(i);
for (Iterator<Integer> iterator = primes.iterator(); iterator.hasNext();) {
int primeCandidate = iterator.next();
if (primeCandidate == k)
continue; // Always skip yourself
if (primeCandidate == (primeCandidate / k) * k)
iterator.remove();
}
}
return primes;
}
public static void main(String... args) {
int initial = 4000;
for (int i = 0; i < 12; i++) {
int n = initial * i;
long start = System.currentTimeMillis();
List<Integer> result = generatePrimesArrayList(n);
long seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tArrayList Seconds: " + seconds);
start = System.currentTimeMillis();
result = generatePrimesBoolean(n);
seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tBoolean Seconds: " + seconds);
start = System.currentTimeMillis();
result = generatePrimesLinkedList(n);
seconds = System.currentTimeMillis() - start;
System.out.println(result.size() + "\tLinkedList Seconds: " + seconds);
}
}
}
And the results of the last few trials:
3432 ArrayList Seconds: 430
3432 Boolean Seconds: 0
3432 LinkedList Seconds: 90
3825 ArrayList Seconds: 538
3824 Boolean Seconds: 0
3824 LinkedList Seconds: 81
4203 ArrayList Seconds: 681
4203 Boolean Seconds: 0
4203 LinkedList Seconds: 100
4579 ArrayList Seconds: 840
4579 Boolean Seconds: 0
4579 LinkedList Seconds: 111
You don't need to add all possible candidates to the array. You can create a Set to store all non primes.
Also you can start checking at k * k, rather than 2 * k
public void primesTo1000() {
Set<Integer> notPrimes = new HashSet<>();
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2);//explicitly add
primes.add(3);//2 and 3
for (int i = 1; i < (1000 / 6); i++) {
handlePossiblePrime(6 * i - 1, primes, notPrimes);
handlePossiblePrime(6 * i + 1, primes, notPrimes);
}
System.out.println(primes);
}
public void handlePossiblePrime(
int k, List<Integer> primes, Set<Integer> notPrimes) {
if (!notPrimes.contains(k)) {
primes.add(k);
for (int j = k * k; j <= 1000; j += k) {
notPrimes.add(j);
}
}
}
untested code, check corners
Here is a bit packing version of the sieve as suggested in the answer referenced by #Will Ness. Rather than return the nth prime, this version returns a list of primes to n:
public List<Integer> primesTo(int n) {
List<Integer> primes = new ArrayList<>();
if (n > 1) {
int limit = (n - 3) >> 1;
int[] sieve = new int[(limit >> 5) + 1];
for (int i = 0; i <= (int) (Math.sqrt(n) - 3) >> 1; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0) {
int p = i + i + 3;
for (int j = (p * p - 3) >> 1; j <= limit; j += p)
sieve[j >> 5] |= 1 << (j & 31);
}
primes.add(2);
for (int i = 0; i <= limit; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0)
primes.add(i + i + 3);
}
return primes;
}
There seems to be a bug in your updated code that uses a boolean array (it is not returning all the primes).
public static List<Integer> booleanSieve(int n) {
boolean[] primes = new boolean[n + 5];
for (int i = 0; i <= n; i++)
primes[i] = false;
primes[2] = primes[3] = true;
for (int i = 1; i <= n / 6; i++) {
int prod6k = 6 * i;
primes[prod6k + 1] = true;
primes[prod6k - 1] = true;
}
for (int i = 0; i <= n; i++) {
if (primes[i]) {
int k = i;
for (int j = k * k; j <= n && j > 0; j += k) {
primes[j] = false;
}
}
}
List<Integer> primesList = new ArrayList<>();
for (int i = 0; i <= n; i++)
if (primes[i])
primesList.add(i);
return primesList;
}
public static List<Integer> bitPacking(int n) {
List<Integer> primes = new ArrayList<>();
if (n > 1) {
int limit = (n - 3) >> 1;
int[] sieve = new int[(limit >> 5) + 1];
for (int i = 0; i <= (int) (Math.sqrt(n) - 3) >> 1; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0) {
int p = i + i + 3;
for (int j = (p * p - 3) >> 1; j <= limit; j += p)
sieve[j >> 5] |= 1 << (j & 31);
}
primes.add(2);
for (int i = 0; i <= limit; i++)
if ((sieve[i >> 5] & (1 << (i & 31))) == 0)
primes.add(i + i + 3);
}
return primes;
}
public static void main(String... args) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
for (int i = 0; i < 10; i++) {
int n = (int) Math.pow(10, i);
Stopwatch timer = Stopwatch.createUnstarted();
timer.start();
List<Integer> result = booleanSieve(n);
timer.stop();
System.out.println(result.size() + "\tBoolean: " + timer);
}
for (int i = 0; i < 10; i++) {
int n = (int) Math.pow(10, i);
Stopwatch timer = Stopwatch.createUnstarted();
timer.start();
List<Integer> result = bitPacking(n);
timer.stop();
System.out.println(result.size() + "\tBitPacking: " + timer);
}
});
}
0 Boolean: 38.51 μs
4 Boolean: 45.77 μs
25 Boolean: 31.56 μs
168 Boolean: 227.1 μs
1229 Boolean: 1.395 ms
9592 Boolean: 4.289 ms
78491 Boolean: 25.96 ms
664116 Boolean: 133.5 ms
5717622 Boolean: 3.216 s
46707218 Boolean: 32.18 s
0 BitPacking: 117.0 μs
4 BitPacking: 11.25 μs
25 BitPacking: 11.53 μs
168 BitPacking: 70.03 μs
1229 BitPacking: 471.8 μs
9592 BitPacking: 3.701 ms
78498 BitPacking: 9.651 ms
664579 BitPacking: 43.43 ms
5761455 BitPacking: 1.483 s
50847534 BitPacking: 17.71 s
There are several things that could be optimized.
For starters, the "contains" and "removeAll" operations on an ArrayList are rather expensive operations (linear for the former, worst case quadratic for the latter) so you might not want to use the ArrayList for this. A Hash- or TreeSet has better complexities for this, being nearly constant (Hashing complexities are weird) and logarithmic I think
You could look into the sieve of sieve of Eratosthenes if you want a more efficient sieve altogeter, but that would be besides the point of your question about the 6k +-1 trick. It is slightly but not noticably more memory expensive than your solution, but way faster.
Can this approach be much more optimized?
The answer is yes.
I'll start by saying that it is a good idea to use the sieve on a subset of number within a certain range, and your suggesting is doing exactly that.
Reading about generating Primes:
...Furthermore, based on the sieve formalisms, some integer sequences
(sequence A240673 in OEIS) are constructed which they also could be used for generating primes in certain intervals.
The meaning of this paragraph is that your approach of starting with a reduced list of integers was indeed adopted by the academy, but their techniques are more efficient (but also, naturally, more complex).
You can generate your trial numbers with a wheel, adding 2 and 4 alternately, that eliminates the multiplication in 6 * k +/- 1.
public void primesTo1000() {
Set<Integer> notPrimes = new HashSet<>();
ArrayList<Integer> primes = new ArrayList<>();
primes.add(2); //explicitly add
primes.add(3); //2 and 3
int step = 2;
int num = 5 // 2 and 3 already handled.
while (num < 1000) {
handlePossiblePrime(num, primes, notPrimes);
num += step; // Step to next number.
step = 6 - step; // Step by 2, 4 alternately.
}
System.out.println(primes);
}
Probably the most suitable standard datastructure for Sieve of Eratosthenes is the BitSet. Here's my solution:
static BitSet genPrimes(int n) {
BitSet primes = new BitSet(n);
primes.set(2); // add 2 explicitly
primes.set(3); // add 3 explicitly
for (int i = 6; i <= n ; i += 6) { // step by 6 instead of multiplication
primes.set(i - 1);
primes.set(i + 1);
}
int max = (int) Math.sqrt(n); // don't need to filter multiples of primes bigger than max
// this for loop enumerates all set bits starting from 5 till the max
// sieving 2 and 3 is meaningless: n*6+1 and n*6-1 are never divisible by 2 or 3
for (int i = primes.nextSetBit(5); i >= 0 && i <= max; i = primes.nextSetBit(i+1)) {
// The actual sieve algorithm like in your code
for(int j = i * i; j <= n; j += i)
primes.clear(j);
}
return primes;
}
Usage:
BitSet primes = genPrimes(1000); // generate primes up to 1000
System.out.println(primes.cardinality()); // print number of primes
// print all primes like {2, 3, 5, ...}
System.out.println(primes);
// print all primes one per line
for(int prime = primes.nextSetBit(0); prime >= 0; prime = primes.nextSetBit(prime+1))
System.out.println(prime);
// print all primes one per line using java 8:
primes.stream().forEach(System.out::println);
The boolean-based version may work faster for small n values, but if you need, for example, a million of prime numbers, BitSet will outperform it in several times and actually works correctly. Here's lame benchmark:
public static void main(String... args) {
long start = System.nanoTime();
BitSet res = genPrimes(10000000);
long diff = System.nanoTime() - start;
System.out.println(res.cardinality() + "\tBitSet Seconds: " + diff / 1e9);
start = System.nanoTime();
List<Integer> result = generatePrimesBoolean(10000000); // from durron597 answer
diff = System.nanoTime() - start;
System.out.println(result.size() + "\tBoolean Seconds: " + diff / 1e9);
}
Output:
664579 BitSet Seconds: 0.065987717
664116 Boolean Seconds: 0.167620323
664579 is the correct number of primes below 10000000.
This method below shows how to find prime nos using 6k+/-1 logic
this was written in python 3.6
def isPrime(n):
if(n<=1):
return 0
elif(n<4): #2 , 3 are prime
return 1
elif(n%2==0): #already excluded no.2 ,so any no. div. by 2 cant be prime
return 0
elif(n<9): #5, 7 are prime and 6,8 are excl. in the above step
return 1
elif(n%3==0):
return 1
f=5 #Till now we have checked the div. of n with 2,3 which means with 4,6,8 also now that is why f=5
r=int(n**.5) #rounding of root n, i.e: floor(sqrt(n)) r*r<=n
while(f<=r):
if(n%f==0): #checking if n has any primefactor lessthan sqrt(n), refer LINE 1
return 0
if(n%(f+2)==0): #remember her we are not incrementing f, see the 6k+1 rule to understand this while loop steps ,you will see that most values of f are prime
return 0
f=f+6
return 1
def prime_nos():
counter=2 #we know 2,3 are prime
print(2)
print(3) #we know 2,3 are prime
i=1
s=5 #sum 2+3
t=0
n=int(input("Enter the upper limit( should be > 3: "))
n=(n-1)//6 #finding max. limit(n=6*i+1) upto which I(here n on left hand side) should run
while(i<n):#2*(10**6)):
if (isPrime(6*i-1)):
counter=counter+1
print(6*i-1) #prime no
if(isPrime(6*i+1)):
counter=counter+1
print(6*i+1) #prime no
i+=1
prime_nos() #fn. call
Your prime number formula mathematically incorrect ex. take 96 it dividable to 6 96/6=16 so by this logic 97 and 95 must be prime if square root passed but square root of 95 is 9.7467... (passed) so its "prime". But 95 clearly dividable by 5 fast algorithm in c#
int n=100000000;
bool [] falseprimes = new bool[n + 2];
int ed=n/6;
ed = ed * 6;
int md = (int)Math.Sqrt((double)ed);
for (int i = ed; i > md; i-=6)
{
falseprimes[i + 1] = true;
falseprimes[i - 1] = true;
}
md = md / 6;
md = md * 5;
for (int i = md; i > 5; i -= 6)
{
falseprimes[i + 1] = true;
falseprimes[i - 1] = true;
falseprimes[(i + 1)* (i + 1)] = false;
falseprimes[(i-1) * (i-1)] = false;
}
falseprimes[2] = true;
falseprimes[3] = true;
To generate prime numbers using 6 * k + - 1 rule use this algorithm:
int n = 100000000;
int j,jmax=n/6;
boolean[] primes5m6 = new boolean[jmax+1];
boolean[] primes1m6 = new boolean[jmax+1];
for (int i = 0; i <= jmax; i++){
primes5m6[i] = false;
primes1m6[i] = false;
}
for (int i = 1; i <= (int)((Math.sqrt(n)+1)/6)+1; i++){
if (!primes5m6[i]){
for (j = 6*i*i; j <= jmax; j+=6*i-1){
primes5m6[j]=true;
primes1m6[j-2*i]=true;
}
for (; j <= jmax+2*i; j+=6*i-1)
primes1m6[j-2*i]=true;
}
if (!primes1m6[i]){
for (j = 6*i*i; j <= jmax-2*i; j+=6*i+1){
primes5m6[j]=true;
primes1m6[j+2*i]=true;
}
for (; j <= jmax; j+=6*i+1)
primes5m6[j]=true;
}
}
System.out.print(2 + " ");
System.out.print(3 + " ");
for (int i = 1; i <= jmax; i++){
if (!primes5m6[i])
System.out.print((6*i-1) + " ");
if (!primes1m6[i])
System.out.print((6*i+1) + " ");
}

Armstrong number code in Java is not working right

I am completely new to Java and am writing code to check whether a number is an Armstrong number or not in the range 0 to 999.
Please tell me what is wrong. When run on command prompt, it repeatedly prints:
1 is the count
Code:
import java.util.*;
class Armstrong
{
public static void main (String[] args)
{
int sum = 0;
for (int i = 0; i < 1000; i++)
{
int n = i;
int count =0;
while(n > 0)
{
int mod = n % 10;
n = n / 10;
count++;
}
System.out.println(+count+ "is the count");
for (int j = 1; j < count; j++)
{
int val = i % 10;
i= i / 10;
sum = val * val * val + sum;
}
if (sum == i)
{
System.out.println( +i+ "is an Armstrong number");
}
}
}
}
An Armstrong number is a number that is the sum of its own digits each raised to the power of the number of digits.
For starters, you always raise the digits to the power of 3, so your calculation can only work for i between 100 and 999.
Second, you are changing i within your inner loop, so the comparison at the end if (sum==i) will fail, since sum should be compared to the original i.
Next, you don't reset sum to 0 in each iteration of i.
You also skip one of the digits.
This seems to work :
int sum = 0;
for (int i = 100; i < 1000; i++) { // start at 100
sum = 0; // clear the sum in each iteration
int n = i;
int count = 0;
while (n > 0) {
int mod = n % 10;
n = n / 10;
count++;
}
n = i;
for (int j = 0; j < count; j++) { // iterate over all the digits
int val = n % 10;
n = n / 10; // don't change i
sum = val * val * val + sum;
}
if (sum == i) {
System.out.println(i + " is an Armstrong number");
}
}
This returns :
153 is an Armstrong number
370 is an Armstrong number
371 is an Armstrong number
407 is an Armstrong number
There is no need to run three loops. You can do it simpler that way:
for(int i = 0; i < 1000; i++) {
int currNumber = i;
int sum = 0;
while(currNumber != 0)
{
int mod = currNumber % 10;
sum = sum + mod * mod * mod;
currNumber = currNumber / 10;
}
if (i == sum) {
System.out.println(i + " is an Armstrong number");
}
}
Print Armstrong number in java
public class CalculatArmstrong
{
public static void main(String[] args)
{
for(int i=0;i<=2000;i++)
{
int number=i;
int n=number;
int rem;
int arms=0;
while(number>0)
{
rem=number%10;
arms=arms+rem*rem*rem;
number=number/10;
}
if(n==arms)
{
System.out.println(n);
}
}
}
}

Categories