C/C++高精度(加减乘除)算法的实现

yizhihongxing

C/C++高精度算法实现方法

背景

C/C++内置的整型数据类型(int、long等)的取值范围都有限制,例如int类型的取值范围为-2147483648~2147483647,这个取值范围对于绝大部分的算法应用是足够的。但是有时候我们需要进行很大数的计算,此时常规的整型数据类型就无能为力了。这时我们需要实现高精度算法来解决这个问题。

实现

高精度算法的实现思路是将一个整数拆分成很多位的数字进行计算。因为C/C++语言对于数值的处理是以原码的形式存在的,所以我们需要先将数字进行存储,通常方式可以使用字符串来存储数字。然后再对每一位进行计算。

  1. 加法实现

高精度加法的实现思路是把两个数字(用字符串存储)从右向左依次相加,同时在每一位上处理进位的情况。

以C++代码实现如下:

string add(string a, string b) {
    // 确定a和b的长度
    int lena = a.size();
    int lenb = b.size();
    // 将a和b的长度变成一致
    if(lena < lenb) {
        a = string(lenb - lena, '0') + a;
    }
    else {
        b = string(lena - lenb, '0') + b;
    }
    // 定义一个存储结果的字符串
    string res = "";
    // 定义一个进位标记,初值为0
    int carry = 0;
    // 从右向左遍历a和b
    for(int i = a.size() - 1; i >= 0; i--) {
        // 记录当前位的结果
        int tmp = a[i] - '0' + b[i] - '0' + carry;
        // 处理进位
        if(tmp >= 10) {
            tmp = tmp - 10;
            carry = 1;
        }
        else {
            carry = 0;
        }
        // 将当前位的结果转化为字符并拼接到res后面
        res = char(tmp + '0') + res;
    }
    // 处理最高位的进位
    if(carry == 1) {
        res = "1" + res;
    }
    return res;
}

示例:

输入:
a = "12345678888888888888888", b = "87654321111111111111111"
输出:
"a + b = 99999999999999999999999"
  1. 减法实现

高精度减法的实现思路是把两个数字(用字符串存储)从右向左依次相减,同时在每一位上处理借位的情况。

以C++代码实现如下:

string sub(string a, string b) {
    // 确定a和b的长度
    int lena = a.size();
    int lenb = b.size();
    // 将a和b的长度变成一致
    if(lena < lenb) {
        a = string(lenb - lena, '0') + a;
    }
    else {
        b = string(lena - lenb, '0') + b;
    }
    // 定义一个存储结果的字符串
    string res = "";
    // 定义一个借位标记,初值为0
    int borrow = 0;
    // 从右向左遍历a和b
    for(int i = a.size() - 1; i >= 0; i--) {
        // 记录当前位的结果
        int tmp = a[i] - b[i] - borrow;
        // 处理借位
        if(tmp < 0) {
            tmp = tmp + 10;
            borrow = 1;
        }
        else {
            borrow = 0;
        }
        // 将当前位的结果转化为字符并拼接到res后面
        res = char(tmp + '0') + res;
    }
    // 去掉结果前导的0
    while(res.size() > 1 && res[0] == '0') {
        res.erase(res.begin());
    }
    return res;
}

示例:

输入:
a = "12345678888888888888888", b = "87654321111111111111111"
输出:
"a - b = 358135777777777777777"

输入: 
a = "10000000000", b = "9999999998"
输出:
"a - b = 2"
  1. 乘法实现

高精度乘法的实现思路是将两个数字从低位到高位分别相乘,并且将结果进行累加,同时在每一位上处理进位的情况。

以C++代码实现如下:

string mul(string a, string b) {
    // 确定a和b的长度
    int lena = a.size();
    int lenb = b.size();
    // 定义一个长度为lena+lenb的数组,初值均为0
    vector<int> c(lena + lenb, 0);
    // 从右向左遍历a和b
    for(int i = lena - 1; i >= 0; i--) {
        for(int j = lenb - 1; j >= 0; j--) {
            // 计算当前位的结果并累加
            int tmp = (a[i] - '0') * (b[j] - '0');
            c[i + j] += tmp % 10;
            c[i + j + 1] += tmp / 10;
        }
    }
    // 处理进位
    for(int i = lena + lenb - 1; i > 0; i--) {
        c[i - 1] += c[i] / 10;
        c[i] %= 10;
    }
    // 将数字转换成字符串
    string res = "";
    for(int i = 0; i < lena + lenb; i++) {
        res += char(c[i] + '0');
    }
    // 去掉结果前导的0
    while(res.size() > 1 && res[0] == '0') {
        res.erase(res.begin());
    }
    return res;
}

示例:

输入:
a = "3141592653589793238462643383279502884197169399375105820974944592", b = "2718281828459045235360287471352662497757247093699959574966967627"
输出:
"a * b = 85397342226735670654635508695465744950348885357651149662156214958094829692774015306456435171075655103989388185261594431010553162683782209088885183430857083831676959258194215804621791426607152452534528352428316383551154792000582925623300905832561334310302899241416157204237264096195863152023724147832970239182246213377282028626077162163681257860606926376734359426968205904903894678404735676246505432122003775"
  1. 除法实现

高精度除法的实现思路是将被除数和除数从高位到低位进行判断,每一位上的计算除法和余数。这里通过类似手算竖式的方式实现。

以C++代码实现如下:

// 高精度除法,返回a/b的结果
string div(string a, string b) {
    string res = "";    // 存储结果的字符串
    string r = "";      // 存储余数的字符串
    for(int i = 0; i < a.size(); i++) {
        r += a[i];      // 逐渐添加数字,计算当前的余数
        int d = 0;      // 当前位商的值
        // 如果当前的余数长度小于除数的长度,则直接添加0
        if(r.size() < b.size()) {
            res += '0';
        }
        else {
            // 在余数大于等于除数的情况下,逐渐减掉除数
            while(r >= b) {
                r = sub(r, b);  // 减去除数(使用高精减法)
                d++;
            }
            // 将当前的商添加到结果字符串当中
            res += char(d + '0');
        }
    }
    // 去掉结果前导的0
    while(res.size() > 1 && res[0] == '0') {
        res.erase(res.begin());
    }
    return res;
}

示例:

输入:
a = "2147483648", b = "123456789"
输出:
"a / b = 17"

输入:
a = "1000000000000000000000", b = "123456789"
输出:
"a / b = 8100000000"

总结

高精度算法是解决基础算法的常见问题之一。本文介绍了高精度算法的C/C++实现方法,并且提供了加法、减法、乘法、除法的示例程序,希望对读者有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C/C++高精度(加减乘除)算法的实现 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • 基于C语言中段错误的问题详解

    基于C语言中段错误的问题详解 什么是段错误 在使用C语言开发时,经常会出现段错误(Segmentation Fault)的问题。所谓段错误,是指程序在访问某个内存地址时,访问了不该访问的内存,或者访问了系统保护的内存区域,导致程序崩溃。通常这种错误会导致程序退出,并输出类似于“Segmentation Fault”、“core dumped”或者“Bus E…

    C 2023年5月23日
    00
  • C语言系统调用约定

    C语言系统调用约定 在C语言中,系统调用使得程序能够与操作系统进行交互,包括执行I/O操作、内存管理等等。C语言中的系统调用约定是指C语言程序如何调用操作系统提供的系统调用。在不同的操作系统中,系统调用的约定可能不同,因此我们需要针对不同的操作系统学习和使用不同的系统调用约定。 基本概念 在C语言中,我们可以使用syscall函数进行系统调用。syscall…

    C 2023年5月23日
    00
  • C语言中常用的几个头文件及库函数

    下面我来详细讲解一下“C语言中常用的几个头文件及库函数”。 常用的头文件 #include stdio.h 是C语言中用来进行输入输出(IO)操作的头文件。常见的IO函数有: printf: 打印输出。 scanf: 读入输入。 getchar: 读入单个字符。 示例: #include <stdio.h> int main() { printf…

    C 2023年5月22日
    00
  • 使用C语言实现扫雷小游戏

    下面我将为你详细讲解使用 C 语言实现扫雷小游戏的完整攻略。 1. 题目描述 这是一个扫雷小游戏,玩家需要在雷区中揭示隐藏的地雷,并且不踩雷,最终揭示出所有非地雷的位置才能胜利。游戏中将提供以下需要的功能: 初始化雷区和地雷 展开被点击的单元格 计算相邻单元格中地雷的数量 判断游戏是否胜利 表示输赢结果 2. 实现思路 游戏思路以及实现可以分为以下几个步骤:…

    C 2023年5月23日
    00
  • C++ 如何将Lambda转换成函数指针

    要将 C++ 中的 Lambda 表达式转换成函数指针,需要使用到一种特殊的转换方式,也就是将 Lambda 表达式转换成函数指针类型。 Lambda 表达式是一种可调用对象,它往往是为了满足某些特定的需求而创建的,而将 Lambda 表达式转换成函数指针则可以让它更加灵活地应用于程序的不同场景。下面是具体的转换攻略: 步骤1:定义 Lambda 表达式 首…

    C 2023年5月23日
    00
  • C语言详细分析讲解多文件的程序设计

    关于C语言多文件程序设计的攻略,我们可以分为以下几个部分进行讲解。 1. 模块化设计思想 在C语言中,模块化设计思想非常重要。它可以帮助我们将程序分解成多个模块,每个模块负责独立的功能,从而提高程序的可读性、可维护性和可重用性。在多文件程序设计中,每个源文件都可以看作一个模块。模块之间可以通过函数和变量进行交互,以此实现程序的功能。 2. 源文件和头文件 在…

    C 2023年5月23日
    00
  • Linux中文件系统truncate.c详解

    Linux中文件系统truncate.c详解 什么是truncate.c文件 truncate.c文件是Linux内核中负责处理文件截断操作的核心文件。其主要功能是截断指定文件的长度,可以对文件进行缩短或扩展。在Linux系统的文件系统中,文件截断操作是文件的常用操作之一。 truncate.c文件操作示例 1. 文件截断操作 truncate.c文件主要包…

    C 2023年5月24日
    00
  • FFmpeg开发笔记(二)搭建Windows系统的开发环境

    由于Linux系统比较专业,个人电脑很少安装Linux,反而大都安装Windows系统,因此提高了FFmpeg的学习门槛,毕竟在Windows系统搭建FFmpeg的开发环境还是比较麻烦的。不过若有已经编译好的Windows版本FFmpeg开发包,那就免去了繁琐的Windows编译过程,所以直接安装已编译的FFmpeg开发包,还是相对容易的。在Windows系…

    C 2023年4月30日
    00
合作推广
合作推广
分享本页
返回顶部