You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于byte[]的Karatsuba乘法器实现Bug排查求助

求助:排查不使用BigInteger的Karatsuba算法Bug

我正尝试实现一个不使用BigInteger类、用于计算两个等长byte数组乘积的Karatsuba算法。以下是我的代码,请求帮忙排查其中的Bug:

static public byte[] Karatsuba(byte[] X, byte[] Y, int N)
{
    if (N == 1)
    {
        int result = X[0] * Y[0];
        byte[] resArray = new byte[2] { (byte)(result % 10), (byte)(result / 10) };
        return resArray;
    }

    int half = N / 2;
    byte[] xLow, xHigh, yLow, yHigh;
    Split(X, half, out xLow, out xHigh);
    Split(Y, half, out yLow, out yHigh);

    byte[] z0 = Karatsuba(xLow, yLow, half);
    byte[] z2 = Karatsuba(xHigh, yHigh, half);
    byte[] z1;

    z1 = Karatsuba(Add(xLow, xHigh, half), Add(yLow, yHigh, half), half);
        
    z1 = Subtract(Subtract(z1, z0, half), z2, half);

    byte[] resultArray = new byte[2 * N];
    Array.Copy(z0, 0, resultArray, 0, z0.Length);
    Array.Copy(z1, 0, resultArray, half, z1.Length);
    Array.Copy(z2, 0, resultArray, 2 * half, z2.Length);

    return resultArray;
}

private static void Split(byte[] x, int half, out byte[] low, out byte[] high)
{
    low = new byte[half];
    high = new byte[half];
    Array.Copy(x, 0, low, 0, half);
    Array.Copy(x, half, high, 0, half);
}

private static byte[] Add(byte[] a, byte[] b, int length)
{
    byte[] result = new byte[length];
    byte carry = 0;

    for (int i = length - 1; i >= 0; i--)
    {
        byte sum = (byte)(a[i] + b[i] + carry);
        result[i] = (byte)(sum % 10);
        carry = (byte)(sum / 10);
    }

    return result;
}

private static byte[] Subtract(byte[] a, byte[] b, int length)
{
    int n = length;
    byte[] result = new byte[n];
    int carry = 0;

    for (int i = n - 1; i >= 0; i--)
    {
        int sub = a[i] - b[i]-carry;
        if (sub < 0)
        {
            sub += 10;
            carry = 1;
        }
        else
        {
            carry = 0;
        }

        result[i] = (byte)sub;
    }

    return result;
}

测试情况

  • N = 4,X = 2185(对应byte数组[5,8,1,2],低位在前),Y = 2185,输出结果为04416205,预期结果为04774225;
  • 部分测试用例正常:N = 2,X = 11(对应byte数组[1,1]),Y = 22(对应byte数组[2,2]),输出结果0242与预期一致,且右侧首位数字总是符合预期。

问题分析与修复方案

1. 核心Bug点梳理

(1) 加减方法遍历方向错误

你的数组采用低位在低索引的存储方式(比如2185存在[5,8,1,2]中,索引0是个位),但Add和Subtract方法却从高位索引(length-1)开始计算,完全搞反了进位/借位的处理顺序,这是导致计算错误的核心原因。

(2) 加法未处理最终进位

两个length位的数相加可能产生最高位进位(比如99+99=198),原Add方法直接丢弃了这个进位,导致后续Karatsuba计算的输入长度缺失,结果偏差。

(3) 减法的长度参数错误

计算z1 = (xLow+xHigh)*(yLow+yHigh) - z0 - z2时,z1、z0、z2的长度都是2*half,但你传入half作为减法的长度参数,直接截断了高位数据,导致减法结果完全错误。

(4) 结果合并未处理进位

原代码只是将z0、z1、z2直接拷贝到对应位置,没有处理不同数位叠加产生的进位(比如z0的高位和z1的低位相加可能进位),最终结果的数位叠加逻辑失效。


2. 修复后的完整代码

static public byte[] Karatsuba(byte[] X, byte[] Y)
{
    // 统一输入长度,补0对齐
    int maxLen = Math.Max(X.Length, Y.Length);
    if (X.Length < maxLen) Array.Resize(ref X, maxLen);
    if (Y.Length < maxLen) Array.Resize(ref Y, maxLen);

    // 终止条件:单数位相乘
    if (maxLen == 1)
    {
        int result = X[0] * Y[0];
        byte[] resArray = result >= 10 ? new byte[2] { (byte)(result % 10), (byte)(result / 10) } : new byte[1] { (byte)result };
        return resArray;
    }

    int half = (maxLen + 1) / 2;
    byte[] xLow, xHigh, yLow, yHigh;
    Split(X, half, out xLow, out xHigh);
    Split(Y, half, out yLow, out yHigh);

    byte[] z0 = Karatsuba(xLow, yLow);
    byte[] z2 = Karatsuba(xHigh, yHigh);
    byte[] sumX = Add(xLow, xHigh);
    byte[] sumY = Add(yLow, yHigh);
    byte[] z1 = Karatsuba(sumX, sumY);
        
    z1 = Subtract(Subtract(z1, z0), z2);

    // 移位相加:z0不移位,z1左移half位,z2左移2*half位
    byte[] shiftedZ1 = ShiftLeft(z1, half);
    byte[] shiftedZ2 = ShiftLeft(z2, 2 * half);
    byte[] temp = AddArrays(z0, shiftedZ1);
    byte[] resultArray = AddArrays(temp, shiftedZ2);

    // 确保输出长度为2*原输入长度,补0对齐
    if (resultArray.Length < 2 * maxLen)
    {
        Array.Resize(ref resultArray, 2 * maxLen);
    }
    return resultArray;
}

private static void Split(byte[] x, int half, out byte[] low, out byte[] high)
{
    low = new byte[half];
    high = new byte[x.Length - half];
    Array.Copy(x, 0, low, 0, half);
    Array.Copy(x, half, high, 0, x.Length - half);
}

// 支持任意长度的数组加法,低位在前
private static byte[] Add(byte[] a, byte[] b)
{
    int maxLen = Math.Max(a.Length, b.Length);
    byte[] result = new byte[maxLen + 1];
    byte carry = 0;

    for (int i = 0; i < maxLen; i++)
    {
        byte digitA = i < a.Length ? a[i] : (byte)0;
        byte digitB = i < b.Length ? b[i] : (byte)0;
        int sum = digitA + digitB + carry;
        result[i] = (byte)(sum % 10);
        carry = (byte)(sum / 10);
    }

    if (carry > 0)
    {
        result[maxLen] = carry;
    }
    else
    {
        Array.Resize(ref result, maxLen);
    }
    return result;
}

// 支持任意长度的数组减法(确保a >= b,符合Karatsuba场景),低位在前
private static byte[] Subtract(byte[] a, byte[] b)
{
    byte[] result = new byte[a.Length];
    int borrow = 0;

    for (int i = 0; i < a.Length; i++)
    {
        byte digitA = a[i];
        byte digitB = i < b.Length ? b[i] : (byte)0;
        int sub = digitA - digitB - borrow;
        if (sub < 0)
        {
            sub += 10;
            borrow = 1;
        }
        else
        {
            borrow = 0;
        }
        result[i] = (byte)sub;
    }

    // 去掉高位多余的0
    int lastNonZero = result.Length - 1;
    while (lastNonZero > 0 && result[lastNonZero] == 0)
    {
        lastNonZero--;
    }
    Array.Resize(ref result, lastNonZero + 1);
    return result;
}

// 数组左移(低位补0,对应乘以10^shift)
private static byte[] ShiftLeft(byte[] arr, int shift)
{
    byte[] result = new byte[arr.Length + shift];
    Array.Copy(arr, 0, result, shift, arr.Length);
    return result;
}

// 多数组通用加法
private static byte[] AddArrays(byte[] a, byte[] b)
{
    int maxLen = Math.Max(a.Length, b.Length);
    byte[] result = new byte[maxLen + 1];
    byte carry = 0;

    for (int i = 0; i < maxLen; i++)
    {
        byte digitA = i < a.Length ? a[i] : (byte)0;
        byte digitB = i < b.Length ? b[i] : (byte)0;
        int sum = digitA + digitB + carry;
        result[i] = (byte)(sum % 10);
        carry = (byte)(sum / 10);
    }

    if (carry > 0)
    {
        result[maxLen] = carry;
    }
    else
    {
        Array.Resize(ref result, maxLen);
    }
    return result;
}

3. 修复说明

  • 调整了Karatsuba方法的入参,不再强制传入长度,自动处理输入对齐;
  • 修正了Add和Subtract的遍历方向,从低位(索引0)开始计算进位/借位;
  • 新增了移位方法和通用数组加法,正确实现Karatsuba的结果合并逻辑;
  • 处理了加法的最终进位和减法的高位冗余0,保证计算精度。

测试修复后的代码,N=4时输入2185×2185,将输出预期的04774225。

内容的提问来源于stack exchange,提问作者NarutoO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:37:00