Recursive Karatsuba multiplication not working? - java

I'm trying to implement Karatsuba multiplication through recursive calls. The code below should work, but I keep getting the wrong answer. Any thoughts?
public static long karatsuba(long x, long y){
//base case:
if (x < 10 || y < 10) return x * y;
//length of digits:
int xSize = String.valueOf(x).length();
int ySize = String.valueOf(y).length();
int N = Math.max(xSize, ySize);
//split each number in half (by length of digits):
long numX_hi = Long.valueOf((String.valueOf(x).substring(0, N/2)));
long numX_lo = Long.valueOf((String.valueOf(x).substring(N/2, xSize)));
long numY_hi = Long.valueOf((String.valueOf(y).substring(0, N/2)));
long numY_lo = Long.valueOf((String.valueOf(y).substring(N/2, ySize)));
//solve multiplications recursively:
long z0 = karatsuba(numX_lo,numY_lo);
long z1 = karatsuba((numX_hi+numX_lo),(numY_hi+numY_lo));
long z2 = karatsuba(numX_hi,numY_hi);
//answer:
return (long)(z2 * Math.pow(10,N)) + (long)((z1-z2-z0) * Math.pow(10,(N/2))) + (z0);
}
Here are a few test cases:
1) karatsuba(1234,5678) >>> 6952652
*should be 7006652
2) karatsuba(4589, 7831) >>> 34649459
*should be 35936459
3) karatsuba(911, 482) >>> 44722
*should be 472842

There are two distinct problems with your method.
Firstly, you should split starting from the last (least significant) digit, not the first. So if you've got these two numbers:
1234
567890
You currently split them like this:
123 4 (123*1000+4)
567 890 (567*1000+890)
This gets you the wrong result because 1234 != 123*1000+4
You should instead split them like this:
1 234 (1*1000+234)
567 890 (567*1000+890)
The second error I discovered happens when you add things back together.
return (long)(z2 * Math.pow(10,N)) + (long)((z1-z2-z0) * Math.pow(10,(N/2))) + (z0);
Will return an incorrect result for odd Ns, as N/2 will be rounded up down and therefore N != ((N/2)*2)
I've combined the two fixes and now I get the correct results:
public static long karatsuba(long x, long y){
//base case:
if (x < 10 || y < 10) return x * y;
//length of digits:
int xSize = String.valueOf(x).length();
int ySize = String.valueOf(y).length();
int halfN = Math.max(xSize, ySize) / 2; // store N/2 instead of N
int splitX = xSize - halfN; // count the split point from xSize down
int splitY = ySize - halfN; // count the split point from ySize down
//split each number in half (by length of digits):
long numX_hi = Long.valueOf((String.valueOf(x).substring(0, splitX)));
long numX_lo = Long.valueOf((String.valueOf(x).substring(splitX)));
long numY_hi = Long.valueOf((String.valueOf(y).substring(0, splitY)));
long numY_lo = Long.valueOf((String.valueOf(y).substring(splitY)));
//solve multiplications recursively:
long z0 = karatsuba(numX_lo,numY_lo);
long z1 = karatsuba((numX_hi+numX_lo),(numY_hi+numY_lo));
long z2 = karatsuba(numX_hi,numY_hi);
//answer:
return (long)(z2 * Math.pow(10,halfN*2)) + (long)((z1-z2-z0) * Math.pow(10,halfN)) + (z0);
}

The accepted solution gives a StringIndexOutOfBoundsException if the length of one number string is more than twice the other, because the splitX or splitY would be negative.
To prevent this problem, one must catch this exception and then set halfN to be Math.min(xSize, ySize)/2 . Here is the corrected code:
public static long karatsuba(long x, long y){
//base case:
if (x < 10 || y < 10) return x * y;
//length of digits:
int xSize = String.valueOf(x).length();
int ySize = String.valueOf(y).length();
int halfN = Math.max(xSize, ySize) / 2; // store N/2 instead of N
if (halfN >= xSize || halfN >= ySize){
halfN = Math.min(xSize, ySize) / 2; // prevents string index error
}
int splitX = xSize - halfN; // count the split point from xSize down
int splitY = ySize - halfN; // count the split point from ySize down
//split each number in half (by length of digits):
long numX_hi = Long.valueOf((String.valueOf(x).substring(0, splitX)));
long numX_lo = Long.valueOf((String.valueOf(x).substring(splitX)));
long numY_hi = Long.valueOf((String.valueOf(y).substring(0, splitY)));
long numY_lo = Long.valueOf((String.valueOf(y).substring(splitY)));
//solve multiplications recursively:
long z0 = karatsuba(numX_lo,numY_lo);
long z1 = karatsuba((numX_hi+numX_lo),(numY_hi+numY_lo));
long z2 = karatsuba(numX_hi,numY_hi);
//answer:
return (long)(z2 * Math.pow(10,halfN*2)) + (long)((z1-z2-z0) * Math.pow(10,halfN)) + (z0);
}

Related

Understanding the strictMath java library

I got bored and decided to dive into remaking the square root function without referencing any of the Math.java functions. I have gotten to this point:
package sqrt;
public class SquareRoot {
public static void main(String[] args) {
System.out.println(sqrtOf(8));
}
public static double sqrtOf(double n){
double x = log(n,2);
return powerOf(2, x/2);
}
public static double log(double n, double base)
{
return (Math.log(n)/Math.log(base));
}
public static double powerOf(double x, double y) {
return powerOf(e(),y * log(x, e()));
}
public static int factorial(int n){
if(n <= 1){
return 1;
}else{
return n * factorial((n-1));
}
}
public static double e(){
return 1/factorial(1);
}
public static double e(int precision){
return 1/factorial(precision);
}
}
As you may very well see, I came to the point in my powerOf() function that infinitely recalls itself. I could replace that and use Math.exp(y * log(x, e()), so I dived into the Math source code to see how it handled my problem, resulting in a goose chase.
public static double exp(double a) {
return StrictMath.exp(a); // default impl. delegates to StrictMath
}
which leads to:
public static double exp(double x)
{
if (x != x)
return x;
if (x > EXP_LIMIT_H)
return Double.POSITIVE_INFINITY;
if (x < EXP_LIMIT_L)
return 0;
// Argument reduction.
double hi;
double lo;
int k;
double t = abs(x);
if (t > 0.5 * LN2)
{
if (t < 1.5 * LN2)
{
hi = t - LN2_H;
lo = LN2_L;
k = 1;
}
else
{
k = (int) (INV_LN2 * t + 0.5);
hi = t - k * LN2_H;
lo = k * LN2_L;
}
if (x < 0)
{
hi = -hi;
lo = -lo;
k = -k;
}
x = hi - lo;
}
else if (t < 1 / TWO_28)
return 1;
else
lo = hi = k = 0;
// Now x is in primary range.
t = x * x;
double c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0)
return 1 - (x * c / (c - 2) - x);
double y = 1 - (lo - x * c / (2 - c) - hi);
return scale(y, k);
}
Values that are referenced:
LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL.
LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L.
LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L.
INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL.
INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L.
INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L.
P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL.
P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L.
P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL.
P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L.
P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L.
TWO_28 = 0x10000000, // Long bits 0x41b0000000000000L
Here is where I'm starting to get lost. But I can make a few assumptions that so far the answer is starting to become estimated. I then find myself here:
private static double scale(double x, int n)
{
if (Configuration.DEBUG && abs(n) >= 2048)
throw new InternalError("Assertion failure");
if (x == 0 || x == Double.NEGATIVE_INFINITY
|| ! (x < Double.POSITIVE_INFINITY) || n == 0)
return x;
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52) & 0x7ff;
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54;
}
exp += n;
if (exp > 0x7fe) // Overflow.
return Double.POSITIVE_INFINITY * x;
if (exp > 0) // Normal.
return Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
if (exp <= -54)
return 0 * x; // Underflow.
exp += 54; // Subnormal result.
x = Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
return x * (1 / TWO_54);
}
TWO_54 = 0x40000000000000L
While I am, I would say, very understanding of math and programming, I hit the point to where I find myself at a Frankenstein monster mix of the two. I noticed the intrinsic switch to bits (which I have little to no experience with), and I was hoping someone could explain to me the processes that are occurring "under the hood" so to speak. Specifically where I got lost is from "Now x is in primary range" in the exp() method on wards and what the values that are being referenced really represent. I'm was asking for someone to help me understand not only the methods themselves, but also how they arrive to the answer. Feel free to go as in depth as needed.
edit:
if someone could maybe make this tag: "strictMath" that would be great. I believe that its size and for the Math library deriving from it justifies its existence.
To the exponential function:
What happens is that
exp(x) = 2^k * exp(x-k*log(2))
is exploited for positive x. Some magic is used to get more consistent results for large x where the reduction x-k*log(2) will introduce cancellation errors.
On the reduced x a rational approximation with minimized maximal error over the interval 0.5..1.5 is used, see Pade approximations and similar. This is based on the symmetric formula
exp(x) = exp(x/2)/exp(-x/2) = (c(x²)+x)/(c(x²)-x)
(note that the c in the code is x+c(x)-2). When using Taylor series, approximations for c(x*x)=x*coth(x/2) are based on
c(u)=2 + 1/6*u - 1/360*u^2 + 1/15120*u^3 - 1/604800*u^4 + 1/23950080*u^5 - 691/653837184000*u^6
The scale(x,n) function implements the multiplication x*2^n by directly manipulating the exponent in the bit assembly of the double floating point format.
Computing square roots
To compute square roots it would be more advantageous to compute them directly. First reduce the interval of approximation arguments via
sqrt(x)=2^k*sqrt(x/4^k)
which can again be done efficiently by directly manipulating the bit format of double.
After x is reduced to the interval 0.5..2.0 one can then employ formulas of the form
u = (x-1)/(x+1)
y = (c(u*u)+u) / (c(u*u)-u)
based on
sqrt(x)=sqrt(1+u)/sqrt(1-u)
and
c(v) = 1+sqrt(1-v) = 2 - 1/2*v - 1/8*v^2 - 1/16*v^3 - 5/128*v^4 - 7/256*v^5 - 21/1024*v^6 - 33/2048*v^7 - ...
In a program without bit manipulations this could look like
double my_sqrt(double x) {
double c,u,v,y,scale=1;
int k=0;
if(x<0) return NaN;
while(x>2 ) { x/=4; scale *=2; k++; }
while(x<0.5) { x*=4; scale /=2; k--; }
// rational approximation of sqrt
u = (x-1)/(x+1);
v = u*u;
c = 2 - v/2*(1 + v/4*(1 + v/2));
y = 1 + 2*u/(c-u); // = (c+u)/(c-u);
// one Halley iteration
y = y*(1+8*x/(3*(3*y*y+x))) // = y*(y*y+3*x)/(3*y*y+x)
// reconstruct original scale
return y*scale;
}
One could replace the Halley step with two Newton steps, or
with a better uniform approximation in c one could replace the Halley step with one Newton step, or ...

How to generate a random number and print some other number?

How do I print a number that is not 'x'. But within the given range.
int x = (int) (Math.random() *3);// I have generated a random number
System.out.println(x);// This will print the random number
There is some confusion understanding this problem so i will explain it with the help of an example.
Suppose 'x' is equal to 2
Now i want to print a number that is not equal to 'x' for example 1, which is within the range stated above.
I would do:
int possibilities = 7;
int x = ThreadLocalRandom.current().nextInt(possibilities);
int y = ThreadLocalRandom.current().nextInt(possibilities - 1);
if (y >= x)
y++; // adding 1 to y here means that y can't equal x
This way y is equally likely to be any of the integers in the range 0 to possibilities - 1 except x.
ThreadLocalRandom.current().nextInt(possibilities); is just an alternative way of generating a random number in a range. ThreadLocalRandom.current() just gives an instance of the Random class, and nextInt is a method for producing random numbers in a range (I prefer this to the Math.random approach).
However, you may find it easier to understand this solution, which is more similar to your original question.
int possibilities = 7;
int x = (int) (Math.random() * possibilities);
int y = (int) (Math.random() * (possibilities - 1));
if (y >= x)
y++;
Try the Random class
Random r = new Random();
int max = 10;
int min = 1;
int x = r.nextInt((max - min) + 1) + min;// I have generated a random number
System.out.println(x);// This will print the random number
I assume you want to print a random number within gives range in java you replace your line
int x = (int) (Math.random() *3);
with this code
Random rand;
int x = rand.nextInt((max - min) + 1) + min;
Given your code:
int x = (int) (Math.random() *3);
int y = (int) (Math.random() *3);
if(y != x){
System.out.println(x);
}

What should I change to make any random generated number positive or negative?

Right now, it makes number above 50 positive and numbers below 50 negative. How should I change the code to make it so that any number can be either positive or negative?
public class P1G
{
static void main()
{
int[] a = new int[10];
for(int index = 0; index < 10; index ++)
{
double r = Math.random();
int p = (int) (((100 - 0) + 1) * r + 0); // (-) or (+)
if ( p < 50 )
{
int n = (int) (((100 - 0) + 1) * r + 0);
n = n * -1;
System.out.println(n);
}
else
{
int n = (int) (((100 - 0) + 1) * r + 0);
n = n;
System.out.println(n);
}
}
}
}
Unless I'm missing something you want
int n = (int) (Math.random() * 101) - 50;
System.out.println(n);
Explanation
Get a random int in the range 0 to 100 and subtract 50, that gives the range -50 to positive 50. Per the Math.random() Javadoc -
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Instead of randoming over [0,101], you can random over [-50, 50] by doing the following:
int p = (int) (100 * r - 50);
Can you just use this?
new Random().nextInt(50)-100
Oh, sorry,, make a big careless mistake.
new Random().nextInt(100) - 50

Integer Factorization

Could anyone explain to me why the algorithm below is an error-free integer factorization method that always return a non-trivial factor of N.
I know how weird this sounds, but I designed this method 2 years ago and still don't understand the mathematical logic behind it, which is making it difficult for me to improve it. It's so simple that it involves only addition and subtraction.
public static long factorX( long N )
{
long x=0, y=0;
long b = (long)(Math.sqrt(N));
long a = b*(b+1)-N;
if( a==b ) return a;
while ( a!= 0 )
{
a-= ( 2+2*x++ - y);
if( a<0 ) { a+= (x+b+1); y++; }
}
return ( x+b+1 );
}
It seems that the above method actually finds a solution by iteration to the diophantine equation:
f(x,y) = a - x(x+1) + (x+b+1)y
where b = floor( sqrt(N) ) and a = b(b+1) - N
that is, when a = 0, f(x,y) = 0 and (x+b+1) is a factor of N.
Example: N = 8509
b = 92, a = 47
f(34,9) = 47 - 34(34+1) + 9(34+92+1) = 0
and so x+b+1 = 127 is a factor of N.
Rewriting the method:
public static long factorX(long N)
{
long x=1, y=0, f=1;
long b = (long)(Math.sqrt(N));
long a = b*(b+1)-N;
if( a==b ) return a;
while( f != 0 )
{
f = a - x*(x+1) + (x+b+1)*y;
if( f < 0 ) y++;
x++;
}
return x+b+1;
}
I'd really appreciate any suggestions on how to improve this method.
Here's a list of 10 18-digit random semiprimes:
349752871155505651 = 666524689 x 524741059 in 322 ms
259160452058194903 = 598230151 x 433211953 in 404 ms
339850094323758691 = 764567807 x 444499613 in 1037 ms
244246972999490723 = 606170657 x 402934339 in 560 ms
285622950750261931 = 576888113 x 495109787 in 174 ms
191975635567268981 = 463688299 x 414018719 in 101 ms
207216185150553571 = 628978741 x 329448631 in 1029 ms
224869951114090657 = 675730721 x 332780417 in 1165 ms
315886983148626037 = 590221057 x 535201141 in 110 ms
810807767237895131 = 957028363 x 847213937 in 226 ms
469066333624309021 = 863917189 x 542952889 in 914 ms
OK, I used Matlab to see what was going here. Here is the result for N=100000:
You are increasing x on each iteration, and the funny pattern of a variable is strongly related with the remainder N % x+b+1 (as you can see in the gray line of the plot, a + (N % (x+b+1)) - x = floor(sqrt(N))).
Thus, I think you are just finding the first factor larger than sqrt(N) by simple iteration, but with a rather obscure criterion to decide it is really a factor :D
(Sorry for the half-answer... I have to leave, I will maybe continue later).
Here is the matlab code, just in case you want it to test by yourself:
clear all
close all
N = int64(100000);
histx = [];
histDiffA = [];
histy = [];
hista = [];
histMod = [];
histb = [];
x=int64(0);
y=int64(0);
b = int64(floor(sqrt(double(N))));
a = int64(b*(b+1)-N);
if( a==b )
factor = a;
else
while ( a ~= 0 )
a = a - ( 2+2*x - y);
histDiffA(end+1) = ( 2+2*x - y);
x = x+1;
if( a<0 )
a = a + (x+b+1);
y = y+1;
end
hista(end+1) = a;
histb(end+1) = b;
histx(end+1) = x;
histy(end+1) = y;
histMod(end+1) = mod(N,(x+b+1));
end
factor = x+b+1;
end
figure('Name', 'Values');
hold on
plot(hista,'-or')
plot(hista+histMod-histx,'--*', 'Color', [0.7 0.7 0.7])
plot(histb,'-ob')
plot(histx,'-*g')
plot(histy,'-*y')
legend({'a', 'a+mod(N,x+b+1)-x', 'b', 'x', 'y'}); % 'Input',
hold off
fprintf( 'factor is %d \n', factor );
Your method is a variant of trial multiplication of (n-a)*(n+b), where n=floor(sqrt(N)) and b==1.
The algorithm then iterates a-- / b++ until the difference of the (n-a)*(n+b) - N == 0.
The partial differences (in respect of a and b) are in proportion to 2b and 2a respectively. Thus no true multiplication are necessary.
The complexity is a linear function of |a| or |b| -- the more "square" N is, the faster the method converges. In summary, there are much faster methods, one of the easiest to understand being the quadratic residue sieve.
Pardon my c#, I don't know Java.
Stepping x and y by 2 increases algorithm speed.
using System.Numerics; // needed for BigInteger
/* Methods ************************************************************/
private static BigInteger sfactor(BigInteger k) // factor odd integers
{
BigInteger x, y;
int flag;
x = y = iSqrt(k); // Integer Square Root
if (x % 2 == 0) { x -= 1; y += 1; } // if even make x & y odd
do
{
flag = BigInteger.Compare((x*y), k);
if (flag > 0) x -= 2;
y += 2;
} while(flag != 0);
return x; // return x
} // end of sfactor()
// Finds the integer square root of a positive number
private static BigInteger iSqrt(BigInteger num)
{
if (0 == num) { return 0; } // Avoid zero divide
BigInteger n = (num / 2) + 1; // Initial estimate, never low
BigInteger n1 = (n + (num / n)) >> 1; // right shift to divide by 2
while (n1 < n)
{
n = n1;
n1 = (n + (num / n)) >> 1; // right shift to divide by 2
}
return n;
} // end iSqrt()

Split 4 digit integer in Java

I want to split a 4-digit integer in to 2. i.e convert 1234 into two variables; x=12 and y=34. Using Java.
int four = 1234;
int first = four / 100;
int second = four % 100;
the first one works because integers are always rounded down, stripping the last two digits when divided by 100.
the second one is called modulo, dividing by 100 and then taking the rest. this strips all digits exept the first two.
Lets say you have a variable number of digits:
int a = 1234, int x = 2, int y = 2;
int lengthoffirstblock = x;
int lengthofsecondblock = y;
int lengthofnumber = (a ==0) ? 1 : (int)Math.log10(a) + 1;
//getting the digit-count from a without string-conversion
How can I count the digits in an integer without a string cast?
int first = a / Math.pow(10 , (lengthofnumber - lengthoffirstblock));
int second = a % Math.pow(10 , lengthofsecondblock);
and at the end something usefull if you have cases where the input could be negative:
Math.abs(a);
int a = 1234;
int x = a / 100;
int y = a % 100;
int i = 1234;
int x = 1234 / 100;
int y = i - x * 100;
You can treat it as a string and split it using substring(), or as an integer:
int s = 1234;
int x = s / 100;
int y = s % 100;
If it's originally an int, I'd keep it as an int and do the above.
Note that you need to consider what happens if your input is not four digit. e.g. 123.
In case you want to split the same no:
int number=1234;
int n,x,y; //(here n=1000,x=y=1)
int f1=(1234/n)*x; //(i.e. will be your first splitter part where you define x)
int f2=(1234%n)*y; //(secend splitter part where you will define y)
If you want to split the number in (12*x,34*y){where x=multiple/factor of 12 & y=multiple/factor of 34),then
1234=f(x(12),y(34))=f(36,68)
int number=1234;
int n; //(here n=1000)
int x=3;
int y=2;
int f1=(1234/n)*x; //(i.e. will be your first splitter part where you define x)
int f2=(1234%n)*y; //(secend splitter part where you will define y)
int i = 1234;
int x = i / 100;
int y = i % 100;
int num=1234;
String text=""+num;
String t1=text.substring(0, 2);
String t2=text.substring(2, 4);
int num1=Integer.valueOf(t1);
int num2=Integer.valueOf(t2);
System.out.println(num1+" "+num2);

Categories