首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不使用BigInteger的Karatsuba算法

不使用BigInteger的Karatsuba算法
EN

Stack Overflow用户
提问于 2013-07-08 15:58:21
回答 9查看 7.1K关注 0票数 10

我一直试图在java中实现Karatsuba算法,而不使用BigInteger。我的代码只适用于两个整数相同的情况&具有相同的数字数。我没有得到正确的答案,但是我得到的答案非常接近正确的答案。例如,我在12*12的时候得到149,我不知道我的代码有什么问题,因为我相信我做的一切都是正确的(按书)。这是我的密码。

代码语言:javascript
复制
public static void main(String[] args) {
    long ans=karatsuba(12,12);
    System.out.println(ans);
}

private static long karatsuba(long i, long j) {
    if (i<10 || j<10){
        return i*j;
    }
    int n=getCount(i);
    long a=(long) (i/Math.pow(10, n/2));
    long b=(long) (i%Math.pow(10, n/2));
    long c=(long) (j/Math.pow(10, n/2));
    long d=(long) (j%Math.pow(10, n/2));

    long first=karatsuba(a,c);
    long second=karatsuba(b,d);
    long third=karatsuba(a+b,c+d);

    return ((long) ((first*Math.pow(10, n))+((third-first-second)*Math.pow(10,n/2))+third));
}

private static int getCount(long i) {
    String totalN=Long.toString(i);
    return totalN.length();
}

编辑:

多亏了卫自耀,问题在于把“第三”改为“第二”。不过,我现在有另一个问题,就是:

如果叫karatsuba(1234,5678),我得到的答案是正确的,但是当我调用karatsuba(5678,1234)时,我没有得到正确的答案。有人能知道原因吗?我更新的代码是:

代码语言:javascript
复制
public static void main(String[] args) {
    //wrong answer
    long ans=karatsuba(5678,1234);
    System.out.println(ans);

    //correct answer
    long ans1=karatsuba(1234,5678);
    System.out.println(ans1);
}

private static long karatsuba(long i, long j) {
    if (i<10 || j<10){
        return i*j;
    }

    int n=getCount(i);

    long a=(long) (i/Math.pow(10, n/2));
    long b=(long) (i%Math.pow(10, n/2));
    long c=(long) (j/Math.pow(10, n/2));
    long d=(long) (j%Math.pow(10, n/2));

    long first=karatsuba(a,c);
    long second=karatsuba(b,d);
    long third=karatsuba(a+b,c+d);

    return ((long) ((first*Math.pow(10, n))+((third-first-second)*Math.pow(10, n/2))+second));

}

更新:

我已经设法收集了"n/2“的值,因此它解决了这个问题,但是,如果使用的数字超过四位数,就会出现错误。以下是我更新的代码:

代码语言:javascript
复制
public static void main(String[] args) {
    System.out.println(Math.round(5.00/2));

    //correct answer
    long ans=karatsuba(5678,1234);
    System.out.println(ans);

    //correct answer
    long ans1=karatsuba(1234,5678);
    System.out.println(ans1);

    //wrong answer
    long ans2=karatsuba(102456,102465);
    System.out.println(ans2);
}


private static long karatsuba(long i, long j) {
    if (i<10 || j<10){
        return i*j;
    }

    double n=Math.round(getCount(i));

    long a=(long) (i/Math.pow(10, Math.round(n/2)));
    long b=(long) (i%Math.pow(10, Math.round(n/2)));
    long c=(long) (j/Math.pow(10, Math.round(n/2)));
    long d=(long) (j%Math.pow(10, Math.round(n/2)));

    long first=karatsuba(a,c);
    long second=karatsuba(b,d);

    long third=karatsuba(a+b,c+d);

    return ((long) ((first*Math.pow(10, Math.round(n)))+((third-second-first)*Math.pow(10, Math.round(n/2)))+second));

}

private static double getCount(long i) {
    String totalN=Long.toString(i);

    return totalN.length();
}

如果有人在没有使用BigInteger的情况下想出了更大的数字(超过四位数)的解决方案,那么请告诉我。谢谢。

EN

回答 9

Stack Overflow用户

发布于 2013-07-08 16:06:39

你的公式是错的。

第一* Math.pow(10,n) +(第三-第一秒)* Math.pow(10,n/ 2) +第三

是错误的,公式应该是

第一* Math.pow(10,n) +(第三-第一秒)* Math.pow(10,n/ 2) +第二

维基百科:

代码语言:javascript
复制
z0 = karatsuba(low1,low2)
z1 = karatsuba((low1+high1),(low2+high2))
z2 = karatsuba(high1,high2)
return (z2*10^(m))+((z1-z2-z0)*10^(m/2))+(z0)
票数 5
EN

Stack Overflow用户

发布于 2014-03-04 20:49:28

最后一个错误是圆(N)应该是2*圆(n/2)。对于奇数n,它们明显不同。

关于int n=getCount(i);,它是一个不对称的来源,所以它应该被改变。

为了提高效率,不应该像我在上面的评论中看到的那样,用max(getCount(i),getCount(j))来代替它,而应该用min来代替它。

事实上,卡拉特赛只有在分裂平衡的数字时才有意义。

试着分解使用max和min执行的操作以确保.

票数 2
EN

Stack Overflow用户

发布于 2015-01-19 19:24:26

最后,经过几个小时的思考,我找到了正确的解决方案:

代码语言:javascript
复制
public static long karatsuba(long i, long j) {
    if (i < 10 || j < 10) {
        return i * j;
    }
    double n = Math.round(getCount(i));
    if (n % 2 == 1) {
        n++;
    }
    long a = (long) (i / Math.pow(10, Math.round(n / 2)));
    long b = (long) (i % Math.pow(10, Math.round(n / 2)));
    long c = (long) (j / Math.pow(10, Math.round(n / 2)));
    long d = (long) (j % Math.pow(10, Math.round(n / 2)));

    long first = karatsuba(a, c);
    long second = karatsuba(b, d);
    long third = karatsuba(a + b, c + d);

    return ((long) ((first * Math.pow(10, n)) + ((third - first - second) * Math.pow(10, Math.round(n / 2))) + second));
}

我无法解释为什么n不能是奇数,但是现在乘法对于我编写的一系列测试是正确的。一旦我发现,我会解释这一行为的。

更新:我正在学习算法:设计和分析,第1部分课程关于,并发布了一个关于这个行为的问题。以下是安德鲁·巴顿的回答:

正如其他地方所提到的,分解输入的关键是确保b和d是相同的长度,这样a和c的幂与系数相同。无论这种力量是什么,都会成为你的n/2;因此,10^n中n的值实际上不是输入的总长度,而是n/2*2。

因此,在3位数的情况下,请按照您的示例:

代码语言:javascript
复制
n = 3;   
n/2 = 2;
n != n/2 * 2;

所以在这个例子中,n应该等于n/2 *2=4。

希望这有意义。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17531042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档