I have the following code which provides the correct values for n < 47.
public static int fib(int n) {
int nthTerm = 0;
if (n == 2)
nthTerm = 1;
else {
double goldenRatio = (1 + Math.sqrt(5)) / 2;
nthTerm = (int) (Math.round(Math.pow(goldenRatio, n)
- Math.pow(1 - goldenRatio, n)) / Math.sqrt(5));
if (n % 2 == 1 && n < 45)
nthTerm++;
}
return nthTerm;
}
Any value for n > 46 is out of int range. How could I adapt this approach to work for n > 46?
P.S. I know of BigInteger but am not very adept at it so I would appreciate an example using BigInteger, too.
You can use this for transformated code into BigInteger.
package your.pack
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Created on 3/6/16.
*/
public class Fibonacci {
private static BigDecimal goldenRatio = new BigDecimal((1 + Math.sqrt(5)) / 2);
private static BigDecimal goldenRatioMin1 = goldenRatio.subtract(BigDecimal.ONE);
private static BigDecimal sqrt5 = new BigDecimal(Math.sqrt(5));
private static BigInteger fib(int n) {
BigInteger nthTerm = new BigInteger("0");
if (n == 2)
nthTerm = BigInteger.ONE;
else {
BigDecimal minResult = goldenRatio.pow(n).subtract(goldenRatioMin1.pow(n));
nthTerm = minResult.divide(sqrt5,0).toBigInteger();
if (n % 2 == 1 && n < 45){
nthTerm = nthTerm.add(BigInteger.ONE);
}
}
return nthTerm;
}
private static int fib2(int n) {
int nthTerm = 0;
if (n == 2)
nthTerm = 1;
else {
double goldenRatio = (1 + Math.sqrt(5)) / 2;
nthTerm = (int) (Math.round(Math.pow(goldenRatio, n)
- Math.pow(1 - goldenRatio, n)) / Math.sqrt(5));
if (n % 2 == 1 && n < 45)
nthTerm++;
}
return nthTerm;
}
public static void main(String []args){
System.out.println(
fib(47)
);
}
}
Method fib2 is your code, fib is the transformed into BigInteger. Cheers
Use long instead of using int, and remember to cast the value from Math.round() to long as well (by writing (long) Math.round(...) just as you casted to int) .
The reason you can't use int is because fib(47) is 2971215073 which overflows Java's signed 32-bit int (231-1). You could use a memoization optimization to implement it with BigInteger like,
private static Map<Integer, BigInteger> memo = new HashMap<>();
static {
memo.put(0, BigInteger.ZERO);
memo.put(1, BigInteger.ONE);
}
public static BigInteger fib(int n) {
if (memo.containsKey(n)) {
return memo.get(n);
}
BigInteger v = fib(n - 2).add(fib(n - 1));
memo.put(n, v);
return v;
}
If you use long, you support perfectly the range over 1000; but if you want support all possible value then you need use BigInteger.
A example use long:
public static long fib(int n)
{
long f0 = 1;
long f1 = 1;
long c = 2;
while(c < n)
{
long tmp = f0+f1;
f0 = f1;
f1 = tmp;
c++;
}
return f1;
}
Related
My task is to determine whether the sum of numbers in the Fibonacci series from A to B is divisible by the number D.
I use the fast doubling algorithm to find the required number in the series, and use the formula: Fa + ... + Fb = Fb+2 - 1 - (Fa+1 - 1) - to determine the sum of the series, but this is not enough. For testing, I took a series from A = 10,000,000 to B = 20,000,000, the number D = 987654, the program was executed in 3.3 seconds, this is a lot. Are there ways to optimize my code?
class Solution {
private static Map<BigDecimal, BigDecimal> previousValuesHolder;
static {
previousValuesHolder = new HashMap<>();
previousValuesHolder.put(BigDecimal.ZERO, BigDecimal.ZERO);
previousValuesHolder.put(BigDecimal.ONE, BigDecimal.ONE);
}
private static BigInteger totalSum;
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int nb = in.nextInt();
for (int i = 0; i < nb; i++) {
int a = in.nextInt();
int b = in.nextInt();
int d = in.nextInt();
totalSum = calculateTotalSum(a, b);
System.out.println(checkSum(totalSum, a, b, d));
}
}
private static BigInteger calculateTotalSum(int start, int finish) {
BigInteger res1 = fibDoubleFast(finish + 2).subtract(BigInteger.valueOf(1));
BigInteger res2 = fibDoubleFast(start + 1).subtract(BigInteger.valueOf(1));
return res1.subtract(res2);
}
private static String checkSum(BigInteger sum, int start, int finish, int d) {
BigInteger result = sum.remainder(BigInteger.valueOf(d));
return result.longValue() > 0
? String.format("F_%s + ... + F_%s is NOT divisible by %s", start, finish, d)
: String.format("F_%s + ... + F_%s is divisible by %s", start, finish, d);
}
private static BigInteger fibDoubleFast(int n) {
BigInteger a = BigInteger.ZERO;
BigInteger b = BigInteger.ONE;
int m = 0;
for (int bit = Integer.highestOneBit(n); bit != 0; bit >>>= 1) {
BigInteger d = multiply(a, b.shiftLeft(1).subtract(a));
BigInteger e = multiply(a, a).add(multiply(b, b));
a = d;
b = e;
m *= 2;
if ((n & bit) != 0) {
BigInteger c = a.add(b);
a = b;
b = c;
m++;
}
}
return a;
}
private static BigInteger multiply(BigInteger x, BigInteger y) {
return x.multiply(y);
}
}
For small values of D (less than 2^31, I think) , you could do the whole code using long, and do mod D for every intermediate result.
private static long fibDoubleFastModD(int n, long m) {
...
long d = (...) % m;
long e = (...) % m;
...
}
I'm writing a simple Java program to convert from decimal to binary.
public static int toBinary(int n) {
int result = 0;
while (n >= 1) {
int power = 0;
while ((int) Math.pow(2, power) <= n) {
power++;
}
result += (int) Math.pow(10, power - 1);
n = n - (int) Math.pow(2, power - 1);
}
return result;
}
The program works for n up until 1023, but fails after that and I'm not sure where I did wrong. Can someone help?
Your code has a problem of Integer Overflow.
Binary of 1024 is 10,000,000,000 and the max value an int can hold is 2,147,483,647.
Use an int array to store the number:
public static void convertBinary(int num) {
int[] binary = new int[40];
int index = 0;
while (num > 0) {
binary[index++] = num % 2;
num /= 2;
}
for (int i = index - 1; i >= 0; i--){
System.out.print(binary[i]);
}
}
You can also use the in-built method.
System.out.println(Integer.toBinaryString(1024));
You can also use StringBuilder to store the result:
public static void convertBinary(int num){
StringBuilder binary = new StringBuilder();
while (num > 0){
binary.append(num % 2);
num = num / 2;
}
System.out.println(binary.reverse());
}
Do not use String (immutable) in a loop, always use a StringBuilder (mutable).
I'm trying to resolve the problem from LeetCode https://leetcode.com/problems/nth-magical-number/ . I can submit my solution, but I would like to speed it up, I suppose one of the ways to do so is remove using of collections
class Solution {
private static final int MODULO = (int) (Math.pow(10, 9) + 7);
private static int modulate(final long result) {
return (int) (result % MODULO);
}
private static SortedSet<Integer> steps(final int smaller, final int larger) {
final int lcm = lowestCommonMultiple(smaller, larger);
final SortedSet<Integer> result = new TreeSet<>();
final int max = lcm / smaller;
final int min = lcm / larger;
for (int i = 1; i <= max; i++) {
result.add(i * smaller);
if (i <= min) {
result.add(i * larger);
}
}
return result;
}
private static long nthNonZeroMagicalNumber(final int N, final int smaller, final int larger) {
final SortedSet<Integer> stepsInCycle = steps(smaller, larger);
final long lcm = stepsInCycle.last();
final int inOneCycle = stepsInCycle.size();
final int fullCycleCount = N / inOneCycle;
int count = fullCycleCount * inOneCycle;
final long evaluated = fullCycleCount * lcm;
if (count == N) {
return evaluated;
}
final int remainder = N - count - 1;
return stepsInCycle.toArray(new Integer[stepsInCycle.size()])[remainder] + evaluated;
}
private static int greatestCommonDenominator(int a, int b) {
while (b > 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
private static int lowestCommonMultiple(final int a, final int b) {
return a * (b / greatestCommonDenominator(a, b));
}
public static int nthMagicalNumber(final int N, final int A, final int B) {
if (N == 0) {
return 0;
} else if (A == B) {
final long result = (long) A * (long) N;
return modulate(result);
} else if (N == 1) {
return modulate(Math.min(A, B));
}
return modulate(nthNonZeroMagicalNumber(N, Math.min(A, B), Math.max(A, B)));
}
}
I suppose it is possible to replace it with a standard array or something like that. Thank you in advance guys!
This is an example of how doing with array only instead of SortedSet:
import java.util.Arrays;
import java.util.Objects;
class Solution {
private static final int MODULO = (int) (Math.pow(10, 9) + 7);
private static int modulate(final long result) {
return (int) (result % MODULO);
}
private static Integer[] steps(final int smaller, final int larger) {
final int lcm = lowestCommonMultiple(smaller, larger);
final int max = lcm / smaller;
final int min = lcm / larger;
final Integer[] result = new Integer[max * 2];
int pos = 0;
for (int i = 1; i <= max; i++) {
result[pos++] = (i * smaller);
if (i <= min) {
result[pos++] = (i * larger);
}
}
return Arrays.stream(result)
.filter(Objects::nonNull)
.sorted()
.distinct()
.toArray(Integer[]::new);
}
private static long nthNonZeroMagicalNumber(final int N, final int smaller, final int larger) {
final Integer[] stepsInCycle = steps(smaller, larger);
final long lcm = stepsInCycle[stepsInCycle.length - 1];
final int inOneCycle = stepsInCycle.length;
final int fullCycleCount = N / inOneCycle;
int count = fullCycleCount * inOneCycle;
final long evaluated = fullCycleCount * lcm;
if (count == N) {
return evaluated;
}
final int remainder = N - count - 1;
return stepsInCycle[remainder] + evaluated;
}
private static int greatestCommonDenominator(int a, int b) {
while (b > 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
private static int lowestCommonMultiple(final int a, final int b) {
return a * (b / greatestCommonDenominator(a, b));
}
public static int nthMagicalNumber(final int N, final int A, final int B) {
if (N == 0) {
return 0;
} else if (A == B) {
final long result = (long) A * (long) N;
return modulate(result);
} else if (N == 1) {
return modulate(Math.min(A, B));
}
return modulate(nthNonZeroMagicalNumber(N, Math.min(A, B), Math.max(A, B)));
}
}
If you have an example of value that causes the performance concern, you could use and compare both solutions or post here and I can try to help in adapting.
You don't need a Set or arrays to solve this problem:
public static final long MAX_N = Double.valueOf(Math.pow(10.0, 9.0)).longValue();
public static final long MODULO_VALUE = MAX_N + 7L;
public static long nthMagicalNumber(long n, long a, long b) {
long count = 0L;
long sample = Math.min(a, b);
long result = sample;
do {
result = sample;
long nextA = ((sample / a) * a) + a;
long nextB = ((sample / b) * b) + b;
sample = Math.min(nextA, nextB);
count++;
} while(count < n);
return result % MODULO_VALUE;
}
I'm using binary search to write a simple square root calculator that takes in doubles in Java. When I tried to test my code by printing out the answer in the main function, however, nothing got printed out in the terminal. I also got errors Possible lossy conversion from double to float......
Here is my code:
public class MyMath{
public static double sqrt(double n){
double u = 1;
double l = 0;
float m = (u + l) / 2;
double norm_input = 1;
float acc = 0.00000000001;
double answer = 0;
if ((n > 0) && (n < 1)){
if ((m * m) < n){
l = m;
}else{
u = m;
}
answer = (u + l) / 2;
return answer;
}else{
int count = 0;
while (n > 1){
n = n / 4;
norm_input = norm_input * 2;
count++;
}
while ((u - l) > acc){
if ((m * m) < n){
l = m;
}else{
u = m;
}
}
answer = (u + l) / 2 * norm_input;
return answer;
}
}
public static void main(String[] args){
double a = new MyMath().sqrt(4);
System.out.println(a);
}
}
It is stuck in infinite loop in second while condition, that's the reason it is not printing values to console.
float m = (u + l) / 2;
Here you have to type cast into float because when two datatype variable participated in division the result would be in higher data type.
float acc = 0.00000000001;
Here also you have type cast because by default java treats a decimal point value as Double.
while ((u - l) > acc){
if ((m * m) < n){
l = m;
}
}
and your code here is going to infinite loop .
I recently came across a problem where given a l and r you need to find out the sum of all x such that l <= x <= r (mod10^9 + 7).
And,
1 <= l <= r <= 10^18
Let sum(x) be the sum of fibonacci numbers upto x and let fibo(x) be the xth fibonacci number. It is known that
sum(x) = fibo(x+2) - 1
Using this I used this post to calculate the nth fibonacci term in O(logn) time.
I was wondering if it can be done any faster than this. Below is my implementation
public class FastFibonacci {
private static Map<BigInteger, BigInteger> map;
private static BigInteger mod = BigInteger.valueOf(1000000007);
public static BigInteger nthFibonacci(BigInteger num) {
if (num.compareTo(BigInteger.valueOf(2)) <= 0) return BigInteger.ONE;
return solve(num.subtract(BigInteger.ONE)).mod(BigInteger.valueOf(10000));
}
public static BigInteger solve(BigInteger num) {
if (map.get(num) != null) {
return map.get(num);
} else {
BigInteger k = num.divide(BigInteger.valueOf(2));
if (num.mod(BigInteger.valueOf(2)).compareTo(BigInteger.ZERO) == 0) {
// f(2*k)
map.put(num, (solve(k).multiply(solve(k)).mod(mod).add(solve(k.subtract(BigInteger.ONE)).multiply(solve(k.subtract(BigInteger.ONE))).mod(mod)).mod(mod)));
return map.get(num);
} else {
// f(2*k + 1)
map.put(num, (solve(k).multiply(solve(k.add( BigInteger.ONE))).mod(mod).add(solve(k).multiply(solve(k.subtract(BigInteger.ONE))).mod(mod))).mod(mod));
return map.get(num);
}
}
}
public static void main(String[] args) {
InputReader in = new InputReader(System.in);
map = new HashMap<>();
map.put(BigInteger.ZERO, BigInteger.ONE);
map.put(BigInteger.ONE, BigInteger.ONE);
int test = in.nextInt();
BigInteger[] ls = new BigInteger[test];
BigInteger[] rs = new BigInteger[test];
for (int i = 0; i < test; i++) {
ls[i] = new BigInteger(in.readString());
rs[i] = new BigInteger(in.readString());
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < test; i++) {
BigInteger sumUptoL = nthFibonacci(ls[i]).subtract(BigInteger.ONE);
BigInteger sumUptoR = nthFibonacci(rs[i].add(BigInteger.valueOf(1))).subtract(BigInteger.ONE);
sb.append(sumUptoR.subtract(sumUptoL));
sb.append("\n");
}
System.out.print(sb.toString());
}
}
Assuming that for a given number N you only want to know fib(N+2)-1 and you don't really need to show all the sequence, you can use a non-recursive approach. The following function uses double, but you can refactor it to BigInteger to accept bigger values:
public double getFibonacci(int n) {
double f1 = Math.pow(((1 + Math.sqrt(5)) / 2.0), n);
double f2 = Math.pow(((1 - Math.sqrt(5)) / 2.0), n);
return Math.floor((f1 - f2) / Math.sqrt(5));
}