高精度

高精度

  对于一些比较庞大的数据量来说,变量是无法储存的,这是就会发生溢出,像我们常用的基本数据数据类型,它们存储数据的大小是有限的。

  • 整型
    • bool : 其值为 true (非0值,常解释为 1) 或 false (值为0)
    • char : 通常占1个字节,取值范围是 \(-127\) ~ \(128\)
    • signed char : 取值范围是 \(-127\) ~ \(128\)
    • unsigned char :取值范围是 \(0\) ~ \(255\)
    • short : 通常占2各字节,取值范围是 \(-2^{15}\) ~ \(2^{15} - 1\)
    • unsigned short :取值范围是 \(0\) ~ \(2^{16} - 1\)
    • int : 通常占4字节,取值范围是 \(-2^{31}\) ~ \(2^{31}-1\)
    • unsigned int: 取值范围是 \(0\) ~ \(2^{32} - 1\)
    • long : 通常占4个字节 取值范围是 \(-2^{31}\) ~ \(2^{31}-1\)
    • unsigned long : 取值范围是 \(0\) ~ \(2^{32} - 1\)
    • long long : 通常占8个字节, 取值范围是 \(-2^{63}\) ~ \(2^{63} - 1\)
    • unsigned long long : 取值范围是 \(0\) ~ \(2^{64} - 1\)

PS:C++规定,int 至少和 short 一样大,long 至少和 int 一样大,long long 至少和 long 一样大,其中,long long 是在 C++11 中新定义的。

  • 浮点类型:
    • float : 通常使用32位内存 ,精度为6~7位有效数字,范围为\(-2^{128}\) ~ \(+2^{128}\),也即-3.40E+38 ~ +3.40E+38。
    • double: 通常使用 64 为内存,精度为15~16位,范围为\(-2^{1024}\) ~ \(+2^{1024}\),也即-1.79E+308 ~ +1.79E+308。
    • long double : 通常使用 80,96,128 位内存 精度为18~19

  这个时候,就可以用数组,字符串来储存数据的每一位了,通常高精度有四种常见场景。

高精度加法

  对于两个数加法的高精度处理,相关的例题有P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)思路就是用字符串将每位数储存,逐个相加,如果结果大于10,就要进位,将计算结果按位储存在数组中,再循环输出,代码可能显得比较臃肿,但好在思路清晰,望见谅。

#include <iostream>  
#include <vector>  
#include <string>  
  
using namespace std;  
  
int main() {  
    //输入两个加数  
    string a, b;  
    cin >> a >> b;  
  
    //特殊情况处理  
    if (a == "0" && b == "0") {  
        cout << "0";  
        return 0;  
    }  
    
    //确定大小  
    int L1 = a.size();  
    int L2 = b.size();  
    int L3 = L1 > L2 ? L1 : L2;  
  
    //构造数组  
    vector<int> va(L3 + 1, 0);  
    vector<int> vb(L3 + 1, 0);  
  
  
    //将每一位储存  
    for (int i = L3, j = L1 - 1; j >= 0; i--, j--) {  
        va[i] = a[j] - '0';  
    }  
    for (int i = L3, j = L2 - 1; j >= 0; i--, j--) {  
        vb[i] = b[j] - '0';  
    }  

	//储存余数
    int x = 0;  
	
	//逐个位数相加
    for (int i = L3; i >= 0; i--) {  
        int temp = va[i];  
        va[i] = (vb[i] + va[i] + x) % 10;  
        //进位处理
        x = (vb[i] + temp + x) / 10;  
    }   

	//处理数组前 "0"
    int i; 
    
    for (i = 0; i <= L3; i++) {  
        if (va[i] != 0) {  
            break;  
        }    }  

	//输出结果
    for (int j = i; j <= L3; j++) {  
        cout << va[j];  
    }  
    return 0;  
}


高精度减法

  对于高精度减法来说,与高精度加法类似,用字符串处理,需要考虑的要点是需要处理借位,就是被减数当前位小于减数当前位,就需要向前一位借 '1',相关的例题有:P2142 高精度减法 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)


#include <string>  
#include <iostream>  
  
using namespace std;  
  
int main() {  
  
  
    bool index = false;  
  
    string a, b;  
    cin >> a >> b;  
  
  
    //判断减数与被减数的大小关系  
    if (a.size() < b.size()) {  
        string temp = a;  
        a = b;  
        b = temp;  
        index = true;  
    } else if (a.size() == b.size()) {  
        if (a < b) {  
            string temp = a;  
            a = b;  
            b = temp;  
            index = true;  
        }    }  
  
    int L1 = a.size();  
    int L2 = b.size();  
  
    //进行补位,让减数与被减数位数相等  
    for (int i = L2; i < L1; i++) {  
        b = '0' + b;  
    }  
  
    int x = 0;  
    for (int i = L1 - 1; i >= 0; i--) {  
  
        int y = (a[i] - '0') - x - (b[i] - '0');  
        x = 0;  
        //借位处理
        if (y < 0) {  
            y += 10;  
            x = 1;  
        }        
        a[i] = char(y + '0');  
    }  
    //输出从非 '0' 开始  
    int i = 0;  
    for (; i < L1; i++) {  
        if (a[i] != '0') {  
            break;  
        }        if (i == L1 - 1) {  
            cout << 0;  
            return 0;  
        }    }  
    //是否输出 '-' 号  
    if (index) {  
        cout << '-';  
    }  
    //输出每一位  
    for (int j = i; j < L1; j++) {  
        cout << a[j];  
    }    return 0;  
}


高精度乘法

  乘法较于加法和减法无疑是麻烦一些,一个乘数的每一位与另个乘数相乘,可以用嵌套循环来解决,乘数固定一个位不变,遍历另一个乘数的每一位与之相乘,这是内循环,一个内循环结束,乘数的位移动,是外循环。相关的题是:P1303 A*B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn),用数组加字符串解决比较方便,思路比较清晰,虽然代码可以优化,但作为初学者,对优化方面没有了解😜。

  
#include <iostream>
#include <vector>
#include <string>
  
using namespace std;  
  
int main() {  
    string a, b;  
    cin >> a >> b;  
	
	//处理特殊情况
    if (a == "0" || b == "0") {  
        cout << 0;  
        return 0;  
    }  
    
    //计算长度  
    int L1 = a.size();  
    int L2 = b.size();  
  
    //转换为数字  
    vector<int> up(L1, 0);  
    vector<int> down(L2, 0);  
    vector<int> res(L1 + L2, 0);  
  
    //个位放在尾部  
    for (int i = 0; i < L1; i++) {  
        up[L1 - 1 - i] = a[L1 - 1 - i] - '0';  
    }  
    for (int i = 0; i < L2; i++) {  
        down[L2 - 1 - i] = b[L2 - 1 - i] - '0';  
    }  
    
    //乘法处理  
  
    for (int i = L2 - 1; i >= 0; i--) { //  down  
        int x = 0;  
        int j, k = 0;  
        for (j = L1 - 1; j >= 0; j--, k++) {  //up  
            int temp = res[L1 + i - k];  //为下方计算进位做打算
            res[L1 + i - k] = (res[L1 + i - k] + down[i] * up[j] + x) % 10;  
            x = (temp + down[i] * up[j] + x) / 10;  
        }        
        
        if (x != 0) {  
            res[i] = x;  
        }    
    }  
    
    //确定首位非零的位置
    int i = 0;  
    for (i; i < L1 + L2; i++) {  
        if (res[i] != 0) {  
            break;  
        }   
    }
	  
	  //输出
    for (int j = i; j < L1 + L2; j++) {  
        cout << res[j];  
    }
      
    return 0;  
}
posted @ 2024-03-20 00:42  KK_LOVE  阅读(4)  评论(0编辑  收藏  举报