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);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/189335.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言进阶之笔试题详解(1)

引言&#xff1a; 对指针知识进行简单的回顾&#xff0c;然后再完成笔试题。 ✨ 猪巴戒&#xff1a;个人主页✨ 所属专栏&#xff1a;《C语言进阶》 &#x1f388;跟着猪巴戒&#xff0c;一起学习C语言&#x1f388; 目录 引言&#xff1a; 知识简单回顾 指针是什么 指针变…

基于51单片机的公交自动报站系统

**单片机设计介绍&#xff0c; 基于51单片机的公交自动报站系统 文章目录 一 概要公交自动报站系统概述工作原理应用与优势 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 很高兴为您介绍基于51单片机的公交自动报站系统&#xff1a; 公交自动报…

[网鼎杯 2020 朱雀组]Nmap

启动环境 结合题目首先就是要知道关于关于nmap命令 相关的命令-oN 标准保存 -oX XML保存 -oG Grep保存 -oA 保存到所有格式 -iL 读取文件内容&#xff0c;以文件内容作为搜索目标 -o 输出到文件 -sP Ping 扫描 还有许多 nmap命令https://blog.csdn.net/weixin_735627…

【知网稳定检索】第九届社会科学与经济发展国际学术会议 (ICSSED 2024)

第九届社会科学与经济发展国际学术会议 (ICSSED 2024) 2024 9th International Conference on Social Sciences and Economic Development 第九届社会科学与经济发展国际学术会议(ICSSED 2024)定于2024年3月22-24日在中国北京隆重举行。会议主要围绕社会科学与经济发展等研究…

java io 流,输入流和输出流;节点流和处理流;字节流和字符流

文章目录 java 中 IO 流分为几种?按照流的流向分&#xff0c;可以分为输入流和输出流&#xff1b;按照流的角色划分为节点流和处理流。IO流主要的分类方式有以下3种&#xff1a; java中的IO流也是工作中使用到比较频繁的一个内容&#xff0c;今天以这篇文章来了解它的概念和整…

快速认识Linux的几个指令

我们先简单认识几个指令&#xff0c;为之后的指令学习打好基础 打开XShell并登录云服务器 01.pwd指令 pwd命令的作用是显示当前在Linux系统中所处的路径 02.ls指令 ls命令的作业是罗列出当前路径下的文件名&#xff08;即pwd的路径下&#xff09;&#xff0c;由于我们没有新…

2023.11.23使用flask实现在指定路径生成文件夹操作

2023.11.23使用flask实现在指定路径生成文件夹操作 程序比较简单&#xff0c;实现功能&#xff1a; 1、前端输入文件夹 2、后端在指定路径生成文件夹 3、前端反馈文件夹生成状态 main.py from flask import Flask, request, render_template import osapp Flask(__name__)a…

WorkPlus即时通讯软件,以自主安全为底座,连接工作的一切

在当今竞争激烈的商业环境中&#xff0c;中大型企业对于移动办公平台的需求越来越迫切。在众多可选的平台中&#xff0c;WorkPlus凭借其高性价比和针对中大型企业的特色功能&#xff0c;成为了许多企业的首选。本文将为各位读者深度解析WorkPlus私有化部署的优势&#xff0c;带…

Co-DETR:DETRs与协同混合分配训练代码学习笔记

关于论文的学习笔记&#xff1a;Co-DETR:DETRs与协同混合分配训练论文学习笔记-CSDN博客 作者提出了一种新的协同混合任务训练方案&#xff0c;即Co-DETR&#xff0c;以从多种标签分配方式中学习更高效的基于detr的检测器。这种新的训练方案通过训练ATSS和Faster RCNN等一对多标…

Proteus仿真--基于PG12864LCD设计的指针式电子钟

本文介绍基于PG12864LCD设计的指针式电子钟&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 本设计中时间芯片选用DS1302芯片&#xff0c;液晶选用PG12864LCD模块&#xff0c;按键K1-K3&#xff0c;K1用于时分选择&#xff0c;K2用于调整功能&#xff0c…

LLaMA 2:开源的预训练和微调语言模型推理引擎 | 开源日报 No.86

facebookresearch/llama Stars: 36.0k License: NOASSERTION LLaMA 2 是一个开源项目&#xff0c;用于加载 LLaMA 模型并进行推理。 该项目的主要功能是提供预训练和微调后的 LLaMA 语言模型的权重和起始代码。这些模型参数范围从 7B 到 70B 不等。 以下是该项目的关键特性…

Docker容器化部署若依微服务ruoyi-cloud项目

系统环境 接下来的内容以 Ubuntu 22.04.1 操作系统为例。 下载安装Docker Ubuntu hihi-IdeaCentre-GeekPro-15ICK:~$ sudo su [sudo] hi 的密码&#xff1a; roothi-IdeaCentre-GeekPro-15ICK:/home/hi# docker ps 找不到命令 “docker”&#xff0c;但可以通过以下软件包安…

C# 使用NPOI操作Excel的工具类

写在前面 NPOI是POI项目的.NET迁移版本。POI是一个开源的Java 读写 Excel、Word 等微软Ole2组件文档的项目&#xff1b;使用NPOI可以在没有安装Office或者相应环境的机器上对Word或Excel文档进行读写操作。 NPOI类库中操作EXCEL有两个模块分别是&#xff1a; 1️.HSSF模块&a…

Java每日一题:26. 删除有序数组中的重复项

删除有序数组中的重复项 分析&#xff1a; 数组是有序的&#xff0c;因此重复的元素会相邻 每次取出两个数进行比较&#xff0c;因此&#xff0c;需要有两个变量去存储每次取出的值 采用双指针方法&#xff1a; 指针p和q&#xff0c; pnum1&#xff0c;qnum2 p和q进行比较&…

一些在使用Python中常用网页字符串处理方法

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 首先一些Python字符串处理的简易常用的用法。 1.去掉重复空格 s "hello hello hello" s .join(s.split())2.去掉所有回车&#xff08;或其他字…

可验证随机函数(VRF)

文章目录 一、背景以及场景共识发展第一代 POW “以力取胜”第二代 POS/DPOS “民主投票”第三代 VRF “运气抽签” 二、可验证随机函数&#xff08;VRF&#xff09;快速开始1. VRF是什么?2. MD5 hash函数和VRF&#xff08;Verifiable Random Function&#xff09;区别3. VRF-…

Java核心知识点整理大全15-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

h5小游戏--2048

2048 经典2048小游戏&#xff0c;基于JS、Html5改写版 效果预览 点我下载源代码 下载代码解压后&#xff0c;双击index.html即可开始本游戏。 Game Rule 游戏规则 以下为游戏默认规则&#xff0c;若需要修改规则请修改代码。 移动箭头键来移动方块&#xff0c;当两个相同数…

visual studio 下的git

我这个是看视频笔记 YouTube : https://www.youtube.com/watch?vgkDASVE_Hdg 主要内容是&#xff1a;建立git 库&#xff0c; 保存commit&#xff0c; 建立分支 create branch, 合并分支merge branch,比较 diff&#xff0c;Revert ,history,delete branch, rename branch, t…

OpenCV快速入门:相机标定——单目视觉和双目视觉

文章目录 前言一、相机标定的基本原理1.1 相机模型与坐标系1.1.1 相机模型1.1.2 坐标系 1.2 相机内参与外参1.2.1 内部参数1.2.2 外部参数 1.3 镜头畸变1.4 透视变换1.5 标定的重要性和应用场景 二、单目视觉2.1 单目视觉的原理2.1.1 单目视觉的原理2.1.2 单目视觉的公式2.1.3 …