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;
...
}
Related
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));
}
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;
}
I'm writing a divide and conquer algorithm but I'm having trouble recursively calling it. It says it cannot find the symbol method Multiply and the variables m, e, m
public class Multiply {
private static int randomInt(int size) {
int maxval = (1 << size) - 1;
return (int)(Math.random()*maxval);
}
public static int[] naive(int size, int x, int y) {
int[] result = new int[3];
if (size == 1) {
result[0] = x*y;
}
else {
int m = size/2;
int a = x/2;
int b = x % (int)Math.pow(2,m);
int c = y / (int)Math.pow(2,m);
int d = y % (int)Math.pow(2,m);
int e = Multiply(a,c,m);
int f = Multiply(b,d,m);
int g = Multiply(b,c,m);
int h = Multiply(a,d,m);
}
return ((int)Math.pow(2,2*m)*e) + ((int)Math.pow(2,m)*(g+h)) + f;
}
Try Multiply.naive(x,y,z) instead of Multiply(x,y,z)
My code looks like this so far:
public class ThreeSort {
public static void main(String[] args) {
int num1 = Integer.parseInt(args[0]);
int num2 = Integer.parseInt(args[1]);
int num3 = Integer.parseInt(args[2]);
int x = Math.min(num1, num2);
int min = Math.min(x,num3);
int z = Math.max(num1, num2);
int max = Math.max(z, num3);
int a = 0;
int mid = 0;
while (mid >= min && mid <= max) {
mid = a;
}
System.out.println(min);
System.out.println(a);
System.out.println(max);
}
I know how to do the min and the max but I'm having troubles with the middle one. Any idea how to do that without conditional statements?
in this case there is a simple algorithm for it:
mid = Math.max(Math.min(num1,num2), Math.min(Math.max(num1,num2),num3));
Also as the operator ^ denotes bitwise xor. so another way is:
mid=num1^num2^num3^max^min;
EXAMPLE:
public static void main(String[] args) {
System.out.println(mid(70, 3, 10));
}
static int mid(int a, int b, int c) {
int mx = Math.max(Math.max(a, b), c);
int mn = Math.min(Math.min(a, b), c);
int md = a ^ b ^ c ^ mx ^ mn;
return md;
}
OUTPUT: 10.
Also as OldCurmudgeon said below you can calculate the mid with below formula:
int mid = num1 + num2 + num3 - min - max;
Put them in a List and sort it...
List<Integer> ints = new LinkedList<>();
ints.add(Integer.parseInt(args[0]));
ints.add(Integer.parseInt(args[1]));
ints.add(Integer.parseInt(args[2]));
Collections.sort(ints); // smallest -> greatest
System.out.println(ints);
Collections.reverse(ints); // greatest -> smallest
System.out.println(ints);
int mid = num1 + num2 + num3 - min - max;
Sorry for briefness - posted from my phone.
It must be self-evident that the middle number is the sum of the three numbers minus the max minus the min. Would also work if max == mid or max == min or even both.
Assuming this is some kind of puzzle/homework are you allowed to use the ternary operator?
int[] ints = {3, 1, 2};
int min = ints[0] <= ints[1] && ints[0] <= ints[2]
? ints[0]
: ints[1] <= ints[0] && ints[1] <= ints[2]
? ints[1]
: ints[2];
This is how I would implement three_sort without any if statements or ternary operators. You would have to adapt this to your language of choice.
def two_sort(a, b):
small = int(a < b) * a + int(a >= b) * b
large = int(a >= b) * a + int(a < b) * b
return small, large
def three_sort(a, b, c):
a, b = two_sort(a, b)
a, c = two_sort(a, c)
b, c = two_sort(b, c)
return a, b, c
for a more general solution:
from random import randint
def two_sort(a, b):
small = int(a < b) * a + int(a >= b) * b
large = int(a >= b) * a + int(a < b) * b
return small, large
return li[-1]
def n_sort(li):
for _ in li:
for i, _ in enumerate(li[:-1]):
li[i], li[i+1] = two_sort(li[i], li[i+1])
return li
N = 10
li = [randint(0, 1000) for _ in range(N)]
print(N_Sort(N)(*li))
public class ThreeSort {
public static void main(String[] args) {
// command-line input
int a = Integer.parseInt(args[0]);
int b= Integer.parseInt(args[1]);
int c = Integer.parseInt(args[2]);
// compute the order
int max=Math.max(Math.max(a,b),c);
int min =Math.min(Math.min(a,b ), c);
int middle = a + b + c - max - min;
// output in ascending order
System.out.println(min+"\n" + middle+ "\n"+ max);
}
}
I had the task to implement RSA algorithm, I read about it in Cormen's book and got most of information from there. I thought it worked good until I faced large p and q primes. For numbers about 250 and lower encryption and decryption works good, however if they are larger, modular exponentation returns negative numbers, which doesn't make sense.
I know that encrypted number can't be larger than n. I read that I can also compute inverse modulo by using extended GCD algorithm and taking x as that value, but when I tried calling extendedEuclid(phi, e)[1] it returned different values than function in RSA class. How can I fix it ?
Here is code for all needed components to compute keys.
Euclid Algorithm
public class Euclid {
public static int euclid(int a, int b) {
if (a < b) {
int tmp = a;
a = b;
b = tmp;
}
if (b == 0) {
return a;
} else {
return euclid(b, a % b);
}
}
public static int[] extendedEuclid(int a, int b) {
if (a < b) {
int tmp = a;
a = b;
b = tmp;
}
if (b == 0) {
return new int[]{a, 1, 0};
} else {
int vals[] = extendedEuclid(b, a % b);
int d = vals[0];
int x = vals[2];
int y = vals[1] - (int) Math.floor(a / b) * vals[2];
return new int[]{d, x, y};
}
}
}
Modular Exponentation
public class Modular {
public static int modularExponentation(int a, int b, int n) {
int c = 0;
int d = 1;
String binaryString = Integer.toBinaryString(b);
for (int i = 0; i < binaryString.length(); i++) {
c = 2 * c;
d = (d * d) % n;
if (binaryString.charAt(i) == '1') {
c = c + 1;
d = (d * a) % n;
}
}
return d;
}
}
RSA generator
public class RsaKeyGenerator {
int d;
int e;
int n;
public RsaKeyGenerator() {
int p = 827;
int q = 907;
n = p * q;
int phi = (p - 1) * (q - 1);
e = computeCoPrime(phi);
d = invMod(e, phi);
System.out.println("Public: " + e);
System.out.println("Private: " + d);
}
private static int computeCoPrime(int phi) {
int e = 2;
while (Euclid.euclid(e, phi) != 1) {
e++;
}
return e;
}
private int invMod(int a, int n) {
int a0, n0, p0, p1, q, r, t;
p0 = 0;
p1 = 1;
a0 = a;
n0 = n;
q = n0 / a0;
r = n0 % a0;
while (r > 0) {
t = p0 - q * p1;
if (t >= 0) {
t = t % n;
} else {
t = n - ((-t) % n);
}
p0 = p1;
p1 = t;
n0 = a0;
a0 = r;
q = n0 / a0;
r = n0 % a0;
}
return p1;
}
public int encrypt(int num) {
return Modular.modularExponentation(num, e, n);
}
public int decrypt(int cipher) {
return Modular.modularExponentation(cipher, d, n);
}
public static void main(String[] args) {
RsaKeyGenerator rsa = new RsaKeyGenerator();
int cip = rsa.encrypt(1343);
System.out.println(cip);
System.out.println(rsa.decrypt(cip));
}
}
The problem you're facing is integer overflow so if you're trying to store a number higher than 2^31 -1 in a signed integer which just isn't possible. So what ends up happening when you hit that limit is that the number wraps around to -2^31 -1.
What you want to do is look into the BigInteger class which will let you store much bigger numbers and should work fine.
The integer overflow happens at this line in the ModularExponentiation class:
d = (d * a) % n;