很长的数字上的 karatsuba 算法错误

Posted

技术标签:

【中文标题】很长的数字上的 karatsuba 算法错误【英文标题】:karatsuba algorithm error on very long numbers 【发布时间】:2021-07-14 01:45:09 【问题描述】:

我了解了 Karatsuba 算法,它允许我使用分治法将非常大的数字相乘。

这是我的代码。我编写了一个返回数字长度的函数,然后编写了乘法函数,并使用该方法进行了 4 次递归调用。

#include <iostream>
#include <algorithm>
#include <math.h>

using namespace std;

int numberLength(long long value) 
    int counter = 0;
    while (value != 0)
    
        counter++;
        value /= 10;
    
    return counter;


long long multiply(long x, long y) 
    int xLength = numberLength(x);
    int yLength = numberLength(y);

    int n = max(xLength, yLength);

    if (n < 10) 
        return x*y;
    

    long multiplier = pow(10, n/2);
    long xS = x/multiplier;
    long xD = x - (xS * multiplier);
    long yS = y/multiplier;
    long yD = y - (yS * multiplier);

    return multiply(xS,yS*pow(10,n)) + multiply(xS,yD*pow(10,n/2)) + multiply(xD,yS*pow(10,n/2)) + multiply(xD,yD);



问题是,如果我用一些长度大于 10 的数字调用函数 multiply(),那么我会得到错误 Segmentation fault。问题出在哪里?

【问题讨论】:

看起来这里没有崩溃:godbolt.org/z/YT3qr61T7。您正在使用任何特定的编译器选项/测试设置吗? pow(10, n/2) 是浮点数,这意味着如果你想要精确的整数,你只能得到 2^532^24 结果值的上限....同样使用 bigint pow 进行 bigint 乘法简直是一个坏事想法.... 【参考方案1】:

您将违反堆栈限制,这将导致长度 >= 10 的数字的递归 multiply() 函数发生堆栈溢出。我尝试了此驱动程序函数

multiply(123456789, 1234567891);

并使用-fsanitize=address 编译它。这是output:

==1==ERROR: AddressSanitizer: stack-overflow on address 0x7fffe22e9fb8 (pc 0x0000004fb85d bp 0x7fffe22ea050 sp 0x7fffe22e9f00 T0)

另外,尝试使用-fsanitize=undefined 编译您的程序以查看逻辑中的其他错误,其中一个是

if (n < 10) 
    return x*y;

传入multiply(123456789, 1234567891) 将导致溢出,因为long(通常为32 位)中无法容纳该值。将其更改为:

if (n < 10) 
    return (long long)x*y;

【讨论】:

以上是关于很长的数字上的 karatsuba 算法错误的主要内容,如果未能解决你的问题,请参考以下文章

Karatsuba乘法--实现大数相乘

不使用 BigInteger 的 Karatsuba 算法

Karatsuba乘法

Karatsuba乘法

[转]大整数算法[11] Karatsuba乘法

数字信号处理--FFT与蝶形算法