C#,《小白学程序》第二十六课:大数乘法(BigInteger Multiply)的Toom-Cook 3算法及源程序

凑数的,仅供参考。

1 文本格式

/// <summary>
/// 《小白学程序》第二十六课:大数(BigInteger)的Toom-Cook 3乘法
/// Toom-Cook 3-Way Multiplication
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static string toom_cook3_multiply(string a, string b)
{
    int n = Math.Max(a.Length, b.Length);
    int[] ra = string_to_digitals(a, n);
    int[] rb = string_to_digitals(b, n);
    toom_cook3_process_00(ra, rb, out int[] rz);
    toom_cook3_carry(rz, n * 2);
    return digitals_to_string(rz);
}

/// <summary>
/// 短数字的乘法(常规乘法,小学生算法)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="z"></param>
private static void toom_cook3_normal(int[] a, int[] b, ref int[] z)
{
    int n = a.Length;
    for (int j = 0; j < n; j++)
    {
        for (int i = 0; i < n; i++)
        {
            z[j + i] += a[i] * b[j];
        }
    }
}

/// <summary>
/// 完全按原始C++代码改写;运行成功;
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="z"></param>
private static void toom_cook3_process_01(int[] a, int[] b, out int[] z)
{
    int n = a.Length;
    int n1 = n * 1 / 3;
    int n2 = n * 2 / 3;
    int n3 = n * 3 / 3;
    int n4 = n * 4 / 3;

    z = new int[n * 2];
    if (n <= 9)
    {
        toom_cook3_normal(a, b, ref z);
        return;
    }

    // int *a0 = &a[0];
    // Multiplicand / right side array pointer
    int a0 = 0;
    // int *a1 = &a[tLen / 3];
    // Multiplicand / central array pointer
    int a1 = n1;
    // int *a2 = &a[tLen * 2/ 3];
    // Multiplicand / left side array pointer
    int a2 = n2;// n * 2 / 3;

    // int *b0 = &b[0];
    // Multiplier / right side array pointer
    int b0 = 0;
    // int *b1 = &b[tLen / 3];
    // Multiplier / central array pointer
    int b1 = n1;
    // int *b2 = &b[tLen * 2 / 3];
    // Multiplier / left side array pointer
    int b2 = n2;// n * 2 / 3;

    // int *c0 = &z[(tLen / 3) * 0];
    int[] c0 = new int[n2];
    int[] c1 = new int[n2];
    // int *c2 = &z[(tLen / 3) * 2];
    int[] c2 = new int[n2];
    int[] c3 = new int[n2];
    // int *c4 = &z[(tLen / 3) * 4];
    int[] c4 = new int[n2];

    int[] a_m2 = new int[n1];  // a(-2)
    int[] a_m1 = new int[n1];  // a(-1)
    int[] a_0 = new int[n1];   // a(0)
    int[] a_1 = new int[n1];   // a(1)
    int[] a_inf = new int[n1]; // a(inf)
    int[] b_m2 = new int[n1];  // b-2)
    int[] b_m1 = new int[n1];  // b-1)
    int[] b_0 = new int[n1];   // b(0)
    int[] b_1 = new int[n1];   // b(1)
    int[] b_inf = new int[n1]; // b(inf)

    // ==== a(-2) = 4 * a2 - 2 * a1 + a0, b(-2) = 4 * b2 - 2 * b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_m2[i] = (a[a2 + i] << 2) - (a[a1 + i] << 1) + a[a0 + i];
        b_m2[i] = (b[b2 + i] << 2) - (b[b1 + i] << 1) + b[b0 + i];
    }
    // ==== c(-2) = a(-2) * b(-2)
    toom_cook3_process_01(a_m2, b_m2, out int[] c_m2);

    // ==== a(-1) = a2 - a1 + a0, b(-1) = b2 - b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_m1[i] = a[a2 + i] - a[a1 + i] + a[a0 + i];
        b_m1[i] = b[b2 + i] - b[b1 + i] + b[b0 + i];
    }
    // ==== c(-1) = a(-1) * b(-1)
    toom_cook3_process_01(a_m1, b_m1, out int[] c_m1);

    // ==== a(0) = a0, b(0) = b0
    for (int i = 0; i < n1; i++)
    {
        a_0[i] = a[a0 + i];
        b_0[i] = b[b0 + i];
    }
    // ==== c(0) = a(0) * b(0)
    toom_cook3_process_01(a_0, b_0, out int[] c_0);

    // ==== a(1) = a2 + a1 + a0, b(1) = b2 + b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_1[i] = a[a2 + i] + a[a1 + i] + a[a0 + i];
        b_1[i] = b[b2 + i] + b[b1 + i] + b[b0 + i];
    }
    // ==== c(1) = a(1) * b(1)
    toom_cook3_process_01(a_1, b_1, out int[] c_1);

    // ==== a(inf) = a2, b(inf) = b2
    for (int i = 0; i < n1; i++)
    {
        a_inf[i] = a[a2 + i];
        b_inf[i] = b[b2 + i];
    }

    // ==== c(inf) = a(inf) * b(inf)
    toom_cook3_process_01(a_inf, b_inf, out int[] c_inf);

    // ==== c4 = 6 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c4[i] = c_inf[i];
    }
    // ==== c3 = -c(-2) + 3 * c(-1) - 3 * c(0) + c(1) + 12 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c3[i] = -c_m2[i];
        c3[i] += (c_m1[i] << 1) + c_m1[i];
        c3[i] -= (c_0[i] << 1) + c_0[i];
        c3[i] += c_1[i];
        c3[i] += (c_inf[i] << 3) + (c_inf[i] << 2);
        c3[i] /= 6;
    }
    // ==== c2 = 3 * c(-1) - 6 * c(0) + 3 * c(1) - 6 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c2[i] = (c_m1[i] << 1) + c_m1[i];
        c2[i] -= (c_0[i] << 2) + (c_0[i] << 1);
        c2[i] += (c_1[i] << 1) + c_1[i];
        c2[i] -= (c_inf[i] << 2) + (c_inf[i] << 1);
        c2[i] /= 6;
    }
    // ==== c1 = c(-2) - 6 * c(-1) + 3 * c(0) + 2 * c(1) - 12 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c1[i] = c_m2[i];
        c1[i] -= (c_m1[i] << 2) + (c_m1[i] << 1);
        c1[i] += (c_0[i] << 1) + c_0[i];
        c1[i] += (c_1[i] << 1);
        c1[i] -= (c_inf[i] << 3) + (c_inf[i] << 2);
        c1[i] /= 6;
    }
    // ==== c0 = 6 * c(0) / 6
    for (int i = 0; i < n2; i++)
    {
        c0[i] = c_0[i];
    }
    // ==== z = c4 * x^4 + c3 * x^3 + c2 * x^2 + c1 * x + c0
    for (int i = 0; i < n2; i++)
    {
        z[i + n4] += c4[i];
        z[i + n3] += c3[i];
        z[i + n2] += c2[i];
        z[i + n1] += c1[i];
        z[i] += c0[i];
    }
}
 


    /// <summary>
    /// 乘积和的进位计算
    /// </summary>
    /// <param name="a"></param>
    /// <param name="n"></param>
    /// <exception cref="Exception"></exception>
    private static void toom_cook3_carry(int[] a, int n)
    {
        int cr = 0;
        for (int i = 0; i < n; i++)
        {
            a[i] += cr;
            if (a[i] < 0)
            {
                cr = -(-(a[i] + 1) / 10 + 1);
            }
            else
            {
                cr = a[i] / 10;
            }
            a[i] -= cr * 10;
        }
        if (cr != 0)
        {
            // Overflow
            throw new Exception("OVERFLOW! cr=" + cr);
        }
    }

2 代码格式

/// <summary>
/// 《小白学程序》第二十六课:大数(BigInteger)的Toom-Cook 3乘法
/// Toom-Cook 3-Way Multiplication
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static string toom_cook3_multiply(string a, string b)
{
    int n = Math.Max(a.Length, b.Length);
    int[] ra = string_to_digitals(a, n);
    int[] rb = string_to_digitals(b, n);
    toom_cook3_process_00(ra, rb, out int[] rz);
    toom_cook3_carry(rz, n * 2);
    return digitals_to_string(rz);
}

/// <summary>
/// 短数字的乘法(常规乘法,小学生算法)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="z"></param>
private static void toom_cook3_normal(int[] a, int[] b, ref int[] z)
{
    int n = a.Length;
    for (int j = 0; j < n; j++)
    {
        for (int i = 0; i < n; i++)
        {
            z[j + i] += a[i] * b[j];
        }
    }
}

/// <summary>
/// 完全按原始C++代码改写;运行成功;
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="z"></param>
private static void toom_cook3_process_01(int[] a, int[] b, out int[] z)
{
    int n = a.Length;
    int n1 = n * 1 / 3;
    int n2 = n * 2 / 3;
    int n3 = n * 3 / 3;
    int n4 = n * 4 / 3;

    z = new int[n * 2];
    if (n <= 9)
    {
        toom_cook3_normal(a, b, ref z);
        return;
    }

    // int *a0 = &a[0];
    // Multiplicand / right side array pointer
    int a0 = 0;
    // int *a1 = &a[tLen / 3];
    // Multiplicand / central array pointer
    int a1 = n1;
    // int *a2 = &a[tLen * 2/ 3];
    // Multiplicand / left side array pointer
    int a2 = n2;// n * 2 / 3;

    // int *b0 = &b[0];
    // Multiplier / right side array pointer
    int b0 = 0;
    // int *b1 = &b[tLen / 3];
    // Multiplier / central array pointer
    int b1 = n1;
    // int *b2 = &b[tLen * 2 / 3];
    // Multiplier / left side array pointer
    int b2 = n2;// n * 2 / 3;

    // int *c0 = &z[(tLen / 3) * 0];
    int[] c0 = new int[n2];
    int[] c1 = new int[n2];
    // int *c2 = &z[(tLen / 3) * 2];
    int[] c2 = new int[n2];
    int[] c3 = new int[n2];
    // int *c4 = &z[(tLen / 3) * 4];
    int[] c4 = new int[n2];

    int[] a_m2 = new int[n1];  // a(-2)
    int[] a_m1 = new int[n1];  // a(-1)
    int[] a_0 = new int[n1];   // a(0)
    int[] a_1 = new int[n1];   // a(1)
    int[] a_inf = new int[n1]; // a(inf)
    int[] b_m2 = new int[n1];  // b-2)
    int[] b_m1 = new int[n1];  // b-1)
    int[] b_0 = new int[n1];   // b(0)
    int[] b_1 = new int[n1];   // b(1)
    int[] b_inf = new int[n1]; // b(inf)

    // ==== a(-2) = 4 * a2 - 2 * a1 + a0, b(-2) = 4 * b2 - 2 * b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_m2[i] = (a[a2 + i] << 2) - (a[a1 + i] << 1) + a[a0 + i];
        b_m2[i] = (b[b2 + i] << 2) - (b[b1 + i] << 1) + b[b0 + i];
    }
    // ==== c(-2) = a(-2) * b(-2)
    toom_cook3_process_01(a_m2, b_m2, out int[] c_m2);

    // ==== a(-1) = a2 - a1 + a0, b(-1) = b2 - b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_m1[i] = a[a2 + i] - a[a1 + i] + a[a0 + i];
        b_m1[i] = b[b2 + i] - b[b1 + i] + b[b0 + i];
    }
    // ==== c(-1) = a(-1) * b(-1)
    toom_cook3_process_01(a_m1, b_m1, out int[] c_m1);

    // ==== a(0) = a0, b(0) = b0
    for (int i = 0; i < n1; i++)
    {
        a_0[i] = a[a0 + i];
        b_0[i] = b[b0 + i];
    }
    // ==== c(0) = a(0) * b(0)
    toom_cook3_process_01(a_0, b_0, out int[] c_0);

    // ==== a(1) = a2 + a1 + a0, b(1) = b2 + b1 + b0
    for (int i = 0; i < n1; i++)
    {
        a_1[i] = a[a2 + i] + a[a1 + i] + a[a0 + i];
        b_1[i] = b[b2 + i] + b[b1 + i] + b[b0 + i];
    }
    // ==== c(1) = a(1) * b(1)
    toom_cook3_process_01(a_1, b_1, out int[] c_1);

    // ==== a(inf) = a2, b(inf) = b2
    for (int i = 0; i < n1; i++)
    {
        a_inf[i] = a[a2 + i];
        b_inf[i] = b[b2 + i];
    }

    // ==== c(inf) = a(inf) * b(inf)
    toom_cook3_process_01(a_inf, b_inf, out int[] c_inf);

    // ==== c4 = 6 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c4[i] = c_inf[i];
    }
    // ==== c3 = -c(-2) + 3 * c(-1) - 3 * c(0) + c(1) + 12 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c3[i] = -c_m2[i];
        c3[i] += (c_m1[i] << 1) + c_m1[i];
        c3[i] -= (c_0[i] << 1) + c_0[i];
        c3[i] += c_1[i];
        c3[i] += (c_inf[i] << 3) + (c_inf[i] << 2);
        c3[i] /= 6;
    }
    // ==== c2 = 3 * c(-1) - 6 * c(0) + 3 * c(1) - 6 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c2[i] = (c_m1[i] << 1) + c_m1[i];
        c2[i] -= (c_0[i] << 2) + (c_0[i] << 1);
        c2[i] += (c_1[i] << 1) + c_1[i];
        c2[i] -= (c_inf[i] << 2) + (c_inf[i] << 1);
        c2[i] /= 6;
    }
    // ==== c1 = c(-2) - 6 * c(-1) + 3 * c(0) + 2 * c(1) - 12 * c(inf) / 6
    for (int i = 0; i < n2; i++)
    {
        c1[i] = c_m2[i];
        c1[i] -= (c_m1[i] << 2) + (c_m1[i] << 1);
        c1[i] += (c_0[i] << 1) + c_0[i];
        c1[i] += (c_1[i] << 1);
        c1[i] -= (c_inf[i] << 3) + (c_inf[i] << 2);
        c1[i] /= 6;
    }
    // ==== c0 = 6 * c(0) / 6
    for (int i = 0; i < n2; i++)
    {
        c0[i] = c_0[i];
    }
    // ==== z = c4 * x^4 + c3 * x^3 + c2 * x^2 + c1 * x + c0
    for (int i = 0; i < n2; i++)
    {
        z[i + n4] += c4[i];
        z[i + n3] += c3[i];
        z[i + n2] += c2[i];
        z[i + n1] += c1[i];
        z[i] += c0[i];
    }
}


    /// <summary>
    /// 乘积和的进位计算
    /// </summary>
    /// <param name="a"></param>
    /// <param name="n"></param>
    /// <exception cref="Exception"></exception>
    private static void toom_cook3_carry(int[] a, int n)
    {
        int cr = 0;
        for (int i = 0; i < n; i++)
        {
            a[i] += cr;
            if (a[i] < 0)
            {
                cr = -(-(a[i] + 1) / 10 + 1);
            }
            else
            {
                cr = a[i] / 10;
            }
            a[i] -= cr * 10;
        }
        if (cr != 0)
        {
            // Overflow
            throw new Exception("OVERFLOW! cr=" + cr);
        }
    }

阅读终点,创作起航,您可以撰写心得或摘录文章要点写篇博文。去创作
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Toom-Cook算法是用于快速乘法的一种算法。它通过将两个数拆分成若干段,然后对每一段分别进行计算,再将结果合并起来得到最终结果。 输入: 两个长度为n的整数数组a和b。 输出: 一个长度为2n-1的整数数组c,表示a和b的乘积。 示例: ``` Input: a=[4, 3, 2, 1], b=[5, 6, 7, 8] Output: c=[20, 38, 44, 34, 8, 5] ``` 程序如下: ```python def toom_cook_multiply(a, b): n = len(a) if n <= 64: return naive_multiply(a, b) m = n // 3 a1, a2, a3 = a[:m], a[m:2*m], a[2*m:] b1, b2, b3 = b[:m], b[m:2*m], b[2*m:] c0 = toom_cook_multiply(a1, b1) c2 = toom_cook_multiply(a3, b3) c1 = toom_cook_multiply(add(a1, a2), add(b1, b2)) c1 = subtract(c1, c0) c1 = subtract(c1, c2) c3 = toom_cook_multiply(add(a2, a3), add(b2, b3)) c3 = subtract(c3, c0) c3 = subtract(c3, c2) c = [] for i in range(n): c.append(c0[i]) for i in range(m): c.append(c1[i]) for i in range(m): c.append(c2[i]) for i in range(n-2*m): c.append(c3[i]) return c ``` 需要注意的是,上面代码需要额外实现add,subtract,naive_multiply三个函数. ### 回答2: Toom-Cook算法是一种将大数乘法问题分解为小数乘法问题的算法。它的基本思想是将两个大数以一定的进制进行分块,然后对每个分块进行小数乘法运算,最终将结果合并得到最终的乘积。 下面是使用Toom-Cook算法改写的程序: ``` import java.math.BigInteger; public class ToomCookMultiplication { public static void main(String[] args) { BigInteger num1 = new BigInteger("1234567890"); BigInteger num2 = new BigInteger("9876543210"); BigInteger result = toomCookMultiply(num1, num2); System.out.println("乘积:" + result); } public static BigInteger toomCookMultiply(BigInteger num1, BigInteger num2) { // 将num1和num2转化为字符串形式 String strNum1 = num1.toString(); String strNum2 = num2.toString(); // 将字符串按照指定大小分块 int blockSize = 2; // 分块大小为2 int numBlocks = (int) Math.ceil((double) Math.max(strNum1.length(), strNum2.length()) / blockSize); String[] blocks1 = splitIntoBlocks(strNum1, numBlocks, blockSize); String[] blocks2 = splitIntoBlocks(strNum2, numBlocks, blockSize); // 对每个分块进行小数乘法运算 BigInteger[] results = new BigInteger[numBlocks]; for (int i = 0; i < numBlocks; i++) { BigInteger block1 = new BigInteger(blocks1[i]); BigInteger block2 = new BigInteger(blocks2[i]); BigInteger blockResult = block1.multiply(block2); results[i] = blockResult; } // 合并所有分块结果得到最终乘积 BigInteger finalResult = BigInteger.ZERO; for (BigInteger r : results) { finalResult = finalResult.add(r); } return finalResult; } public static String[] splitIntoBlocks(String str, int numBlocks, int blockSize) { String[] blocks = new String[numBlocks]; int startIndex = str.length() - blockSize; for (int i = numBlocks - 1; i >= 0; i--) { int endIndex = Math.max(startIndex + 1, 0); blocks[i] = str.substring(endIndex, startIndex + 1); startIndex -= blockSize; } return blocks; } } ``` 这段程序通过Toom-Cook算法大数进行分块,对每个分块进行小数乘法运算,然后将所有分块的结果累加得到最终的乘积。在这个例子中,我们假设要计算的两个数分别是"1234567890"和"9876543210",程序输出结果将是它们的乘积。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值