Karatsuba multiplication not working recursively with BigInteger - java

I am trying to multiply n digit number using karatsuba multiplication.
I am getting output for single digit number (Example 4 and 5 = 20).
But, when I multiply 1234 and 5678 I am getting error and no output result.
I have updated the code and error message. Please check.
The error is Click here
import java.math.BigInteger;
class karatsubamultiplication{
public static BigInteger karat(BigInteger number1, BigInteger number2){
if(number1.bitLength() < 4 && number2.bitLength() < 4)
return number1.multiply(number2);
//Finding maximum length of two
//int m = Math.max(number1, number2);
String first = number1.toString();
String second = number2.toString();
BigInteger a = new BigInteger(first.substring(0, first.length()/2));
BigInteger b = new BigInteger(first.substring(first.length() - first.length()/2, first.length()));
BigInteger c = new BigInteger(second.substring(0, second.length()/2));
BigInteger d = new BigInteger(second.substring(second.length() - second.length()/2, second.length()));
BigInteger ac = karat(a, c);
BigInteger bd = karat(b, d);
BigInteger abcd = karat(a.add(b), c.add(d));
BigInteger z = abcd.subtract(ac.add(bd));
int m = String.valueOf(number1).length();
BigInteger len = new BigInteger(String.valueOf(Math.pow(10, m)));
return (ac.multiply(len)).add(z.multiply(len.divide(BigInteger.valueOf(2)))).add(bd);
}
public static void main(String[] args){
BigInteger result = new BigInteger("0");
BigInteger x = new BigInteger("1234");
BigInteger y = new BigInteger("5678");
result = karat(x, y);
System.out.println(result);
}
}
Please correct the code. I have not checked whether two numbers are equal or not and length is odd or even.
Thank you.

Related

Why is my sequence generating incorrectly?

The goal of the code is to generate a sequence that operates as follows:
The first number is given, 2. To find the next number in the sequence: multiply all numbers in the sequence together than add 1. The smallest prime divisor of that number is the next number in the sequence. The first three number are [2, 3, 7]. So 237 + 1 = 43. The smallest prime factor is 43. So 43 is the next number. However when my code reaches the 5th number in the sequence it generates 139, instead of 13. 237*43 + 1 = 1807. 1807/13 = 139. So 13 should be next.
Problem: When my code reaches the 5th number in the sequence it generates 139
Note: Using BigInteger because reaching the 8th, 9th,... do not work with Int
import java.math.BigInteger;
import java.util.Scanner;
import java.util.ArrayList;
public class LPMSeq {
public static BigInteger spd(BigInteger y) {
ArrayList<BigInteger> primes = new ArrayList<BigInteger>();
int retval = 0;
int Nth_prime = 25200;
BigInteger TWO = new BigInteger("2");
BigInteger bi = new BigInteger("1");
primes.add(TWO);
int i = 1;
//generates N prime numbers using isProbablePrime
while (i < Nth_prime) {
bi = bi.add(TWO);
if (bi.isProbablePrime(80)) {
i++;
primes.add(bi);
}
}
BigInteger zero = new BigInteger("0");
// finds smallest prime divisor
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
}
}
return BigInteger.valueOf(retval);
}
public static ArrayList<BigInteger> LpmSeq(int k) {
//ArrayList holding the sequence
ArrayList<BigInteger> Seq = new ArrayList<BigInteger>();
BigInteger two = new BigInteger ("2");
//Add two to sequence (first number in sequence)
Seq.add(two);
while (Seq.size() < k) {
BigInteger x = new BigInteger ("1");
for (int i = 0; i < Seq.size(); i++) {
x = x.multiply(Seq.get(i));
}
BigInteger y = x.add(BigInteger.ONE);
BigInteger spd = spd(y);
Seq.add(spd);
}
return Seq;
}
public static void main(String[] args) {
//Create Scanner
Scanner userinput = new Scanner(System.in);
// Variables
int k = 0;
//Prompt user and get input
System.out.println("How many elements would you like in the sequence? (Please enter an integer)");
k = userinput.nextInt();
System.out.println(LpmSeq(k));
}
}
Your loop that finds the smallest prime factor doesn't work if y isn't prime:
// finds smallest prime divisor
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
}
}
It finds the largest prime factor, because it doesn't stop when it finds the first prime factor. Because the factorization of 1807 is 13 x 139, it skips 13 and returns 139.
Place a break after you assign retval:
for (int n = 0; n < Nth_prime; n++) {
BigInteger modded = y.mod(primes.get(n));
if (modded.equals(zero)) {
retval = primes.get(n).intValue();
break;
}
}
Also, I find it curious that you're checking all primes through the 25,200th (and re-calculating all 25,200 of them each call). You only need to check primes through the square root of y.

Formula isn't Correctly Calculating

I am trying to figure out why the following is not correctly calculating
x = Math.pow(w,e);
When I calculate it in Java, I get 1075, but I am supposed to get 779.
int e = 17;
int w = 803;
int n = 2773;
double x = 0;
x = Math.pow(w,e) % n;
System.out.println(x);
double floating point numbers have 53 bits of precision, which is not enough to store the exact value of a huge number like 80317. To do modular exponentiation in Java, you can use the modPow method on BigIntegers.
As (803^17) is a very big number so you have to use the BigInteger datatype for the variables used here instead of int or double datatype. We cannot convert the integer or double variable to a BigInteger variable.
So, the program will be :
import java.math.BigInteger;
public class JavaPow {
public static void main(String[] args)
{
BigInteger e = new BigInteger("17");
BigInteger w = new BigInteger("803");
BigInteger n = new BigInteger("2773");
BigInteger x;
x = w.modPow(e,n);
System.out.println(x);
}
}

Performance Improvement For Using BigInteger While Calculating Square Root

I am trying to calculate the square root of all the integers below 100 with A precision of up to 10000 digits. I already tried it using Newton's method with Big Decimal, where it eats a lot of time.
So now am using Jarvis method for finding the square root using BigInteger.(I think this method involves less number of calculations and gets rid of the maintenance of decimal digits). Even then my code takes a lot of time.The following piece of code depicts the calculations.
public class SquareRootHackerRankJarvis {
static BigInteger limit;
static BigInteger a;
static BigInteger b;
private static BigInteger squareroot(int n, int digits, BigInteger ten,
BigInteger hundred, BigInteger five) {
limit = ten.pow(digits + 1);
a = BigInteger.valueOf(n * 5);
b = BigInteger.valueOf(5);
while (b.compareTo(limit) == -1) {
if (a.compareTo(b) != -1) {
a = a.subtract(b);
b = b.add(ten);
} else {
a = a.multiply(hundred);
b = (b.divide(ten)).multiply(hundred).add(five);
}
}
return b.divide(hundred);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int P = scanner.nextInt();
int sum = 0;
int p = 1;
BigInteger ten = BigInteger.valueOf(10);
BigInteger hundred = BigInteger.valueOf(100);
BigInteger five = BigInteger.valueOf(5);
for (int i = 1; i <= N; i++) {
if (p * p == i) {
p++;
continue;
}
BigInteger x = squareroot(i, P, ten, hundred, five);
char[] digits = x.toString().toCharArray();
for (int j = 0; j <= P - 1; j++) {
sum += Character.getNumericValue(digits[j]);
}
}
System.out.println(sum);
scanner.close();
}}
Can anyone provided or suggestions about the proper usage of BigInteger for optimum performance?
Comments on improvement of the above algorithm are also welcomed.
BigInteger ten = BigInteger.valueOf(10);
BigInteger hundred = BigInteger.valueOf(100);
BigInteger five = BigInteger.valueOf(5);
Should be moved outside of the function squareroot so they are not created and initialized every time function is called. Make sure they are still accessible in this function.
BigInteger num;
BigInteger limit;
BigInteger a;
BigInteger b;
Should be created outside of the function and should be only initialized on every fucntion call.
Also following line
b = (b.divide(ten)).multiply(hundred).add(five);
can be optimized to
b = b.multiply(ten).add(five);
One observation beyond fast computation of numerous digits of roots of non-squares is that there are just 25 non-compound numbers from 2 to 100.
Next, in addition to introducing constants like Maciej suggested, reduce the "introduction of 0 before the trailing 5" to two operations:
static final BigInteger
ten = BigInteger.TEN,
oneHundred = BigInteger.valueOf(100),
five = BigInteger.valueOf( 5),
fourtyFive = BigInteger.valueOf( 45);
/** Computes <code>digits</code> decimal digits of <code>n</code>
* <em>ignoring</em> (decimal) scaling. */
private static BigInteger sqrtDigitsJarvis(int n, int digits) {
BigInteger
limit = ten.pow(digits + 1), // might be an instance data member
a = BigInteger.valueOf(n*5L), // la*100),
b = five; // BigInteger.valueOf(ib*10 - 45);
// flawed for limit < sqrt(5n)
while (b.compareTo(limit) < 0) {
if (0 <= a.compareTo(b)) { // each branch can be parallelised
a = a.subtract(b);
b = b.add(ten);
} else {
a = a.multiply(oneHundred);
b = b.multiply(ten).subtract(fourtyFive);
}
}
return b.divide(oneHundred);
}

get random BigInteger in range (x, y) [duplicate]

This question already has answers here:
How to generate a random BigInteger value in Java?
(8 answers)
Closed 8 years ago.
I need to get a random BigInteger that is bigger than 2^511 and lower than 2^512.
byte[] bytes = new byte[64]; // 512 bits
new Random().nextBytes(bytes);
bytes[0] |= 0x80; // set the most significant bit
return new BigInteger(1, bytes);
From the doc :
BigInteger(int numBits, Random rnd)
Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.
So something like that should work :
BigInteger number = new BigInteger(512, new Random()); //Give you a number between 0 and 2^512 - 1
number = number.setBit(0); //Set the first bit so number is between 2^511 and 2^512 - 1
This solution creates at first a BigInteger with value 2^511 and afterwards adds an value between 0 and 2^511 - 1:
StringBuilder builder = new StringBuilder("1");
for (int bit = 0; bit < 511; bit++) builder.append("0");
BigInteger value = new BigInteger(builder.toString(), 2).add(new BigInteger(511, new Random()));
You could try that
public static void main(String[] args) {
int min = 511;
double rand = Math.random(); //between 0 and 1
double exp = min + rand; //between 511 et 512
Double result = Math.pow(2, exp);
System.out.println("result = ["+result+"]");
}
It is maybe not optimised, but its works. With the double result, you can obtain a integer.

Using BigIntegers as a condition in while loop in Java

I want to use a big integer value in my while loop condition but this is not working.
import java.util.Scanner;
import java.util.StringTokenizer;
public class NiceProbelm2 {
public static void main(String[]args){
Scanner input = new Scanner(System.in);
String number = input.nextLine();
StringTokenizer st = new StringTokenizer(number);
BigInteger base = null;
int power=0;
while (st.hasMoreTokens()) {
String token1 = st.nextToken();
String token2 = st.nextToken();
base = new BigInteger(token1);
power = Integer.parseInt(token2);
}
BigInteger result = base.pow(power);
//long fresult = (long)result;
BigInteger div = new BigInteger("10");
System.out.println(result);
BigInteger sum=null;
//NOt working while(result.compareTo(new BigInteger("0")) > 10 )
{
BigInteger digit = result.mod(div);
result = result.divide(div);
sum = sum.add(digit);
}
System.out.println(sum);
}
}
You should never compare the return value of compareTo() to anything other than 0. (BigInteger.compareTo() is a bit more specific, but the same rule still applies)
You can check if it's greater than 0, less than 0 or equal to 0. Only those 3 pieces of information are actually relevant. The actual value (if it returns 1 or 10 or 100) doesn't matter.
I think you problem with the previous solutions were you had a null pointer that was being thrown because your accumulator was not initialized. The following code produces the result you are looking for:
BigInteger result = base.pow(power);
BigInteger div = new BigInteger("10");
System.out.println(result);
//The following line is different, initialize the sum before using it.
BigInteger sum = BigInteger.ZERO;
while(!BigInteger.ZERO.equals(result)) {
BigInteger digit = result.mod(div);
result = result.divide(div);
sum = sum.add(digit);
}
System.out.println(sum);
I also wanted to point out that BigInteger has a method that provides both the quotient and remainder from a single division, which is more efficient than doing them both separately, and there is a "valueOf" method for BigInteger so you can use a numeric literal instead of a string:
BigInteger result = base.pow(power);
BigInteger div = BigInteger.valueOf(10);
System.out.println(result);
//Initialize the sum to zero
BigInteger sum = BigInteger.ZERO;
//While the result has a non-zero decimal digit
while(!BigInteger.ZERO.equals(result)) {
//this divides by ten (first element),
//and calculates the remainder (second element)
BigInteger[] lastDigit = result.divideAndRemainder(div);
result = lastDigit[0];
sum = sum.add(lastDigit[1]);
}
System.out.println(sum);
You have to use this condition:
result.compareTo(BigInteger.ZERO) > 0
It looks like you want to do while (result != 0) which you would write like
while (result.compareTo(BigInteger.ZERO) != 0)
Also, you need to initialize sum to BigInteger.ZERO.

Categories