0.首先,神马是高精度数?
高精度通常指的是能够处理比标准数据类型所能表示的数值范围更大的数值的能力。在计算机科学中,标准的数据类型如`int`、`long`等都有其固定的位宽和数值范围限制。当需要处理的数值超出这些限制时,就需要使用高精度算法或数据结构。
在不同的上下文中,"高精度"可能有不同的含义:
1. **数值计算**:在数值计算中,高精度可能指的是能够处理非常大的整数或小数,这些数值超出了标准整数或浮点数类型的表示范围。例如,处理几千位的整数或具有很多小数位的浮点数。
2. **数据存储**:在数据存储方面,高精度可以指使用更多的位来存储数值,以支持更宽的数值范围。
3. **算法实现**:在算法实现中,高精度通常通过字符串或数组来模拟大数的存储和运算。例如,使用字符串来表示每一位的数字,然后通过模拟手算加法或乘法的过程来进行计算。
4. **时间精度**:在时间相关的应用中,高精度可能指的是时间测量的精度,比如纳秒级别的时间戳。
5. **空间精度**:在地理信息系统(GIS)中,高精度可能指的是位置数据的精度,比如使用经纬度的更多小数位来提高定位的精确度。
在编程中,实现高精度计算的一种常见方法是使用字符串来存储和操作大数,因为字符串可以动态地增长以适应任意长度的数字。这种方法允许程序员绕过标准数据类型的大小限制,进行任意精度的数值运算。
1.高精度求和
在C++中实现高精度加法(字符串)通常涉及到处理两个大数的加法运算,这在标准整数类型无法容纳时非常有用。以下是实现高精度加法的基本思路:
1. **输入处理**:将输入的数字以字符串形式读取,确保可以处理任意长度的数字。
2. **反转字符串**:为了方便从最低位开始加,将输入的字符串数字反转。
3. **初始化变量**:初始化两个指针或索引,分别指向两个待加的字符串的起始位置,以及一个变量来存储进位。
4. **逐位相加**:
- 使用循环遍历两个字符串的每一位,进行相加操作。
- 如果当前位相加的结果加上进位大于等于10,则将结果的个位数作为当前位的结果,并将10进位到下一次循环。
- 否则,直接将相加的结果作为当前位的结果。
5. **进位处理**:在每次循环结束后,检查是否有进位需要加到下一次循环。
6. **结果构建**:在循环结束后,如果存在进位,则将其添加到结果字符串的最前面。
7. **反转结果**:由于之前我们反转了输入的字符串,所以在加法完成后需要再次反转结果字符串,以得到正确的顺序。
8. **输出结果**:将最终的结果输出或返回。
话不多说,上模板代码:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a_str[1001] = {}, b_str[1001] = {}; //输入的加数
int a_int[1001] = {}, b_int[1001] = {}; //转换后参与运算的加数
int len_a, len_b; //a,b的位数
int ans[1001] = {}; //结果
int len_ans = 0; //len_ans本身是没有值,len_ans用来记录最后运算后的结果位数
cin >> a_str >> b_str;//输入
len_a = strlen(a_str);
len_b = strlen(b_str);//获取A,B的位数
int in = 0; //进位变量
for (int i = 0; i < len_a; i++) //倒序转换A
{
a_int[len_a - 1 - i] = a_str[i] - '0';
}
for (int i = 0; i < len_b; i++)
{
b_int[len_b - 1 - i] = b_str[i] - '0';
}
len_ans = max(len_a, len_b);//获取结果位数
for (int i = 0; i < len_ans; i++) //开始计算
{
ans[i] = a_int[i] + b_int[i] + in; //计算逻辑
in = ans[i] / 10; //所有位数均按照有进位处理
ans[i] %= 10;
}
if (in) //判断最高位进位
{
ans[len_ans] = in;
len_ans++;
}
for (int i = len_ans - 1; i >= 0; i--)//倒序输出结果
{
cout << ans[i];
}
return 0;
}
2.高精度减法
在C++中实现高精度减法(字符串)的思路与加法差不多的啦,但有几个关键点需要注意:
-
输入处理:将需要进行减法的两个大数以字符串形式输入。
-
字符串反转:为了从最低位开始处理,将两个字符串反转。
-
长度对齐:确保两个字符串长度相同,如果不同,可以在较短的字符串前面补0。
-
逐位相减:
- 使用循环,从最低位开始,逐位进行减法操作。
- 如果当前位的数值不足以减去,需要向前一位借位。
-
借位处理:
- 当需要借位时,将前一位的数值减1,当前位的数值加10(相当于借了1位)。
-
结果构建:在循环中,逐位构建结果字符串。
-
去除前导零:在减法完成后,如果结果字符串的第一位是0,需要去除,以保持结果的正确性。
-
反转结果:由于之前反转了输入的字符串,所以在减法完成后需要再次反转结果字符串。
-
输出结果:将最终的结果输出或返回。
上代码:
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a_str[1001]= {},b_str[1001]= {}; //被减数与减数
int a_int[1001]= {},b_int[1001]= {},ans[1001]; //计算数组以及结果数组
int len_a=0,len_b=0,len_ans=0;//高精度数长度
cin>>a_str>>b_str;//输入因数
len_a=strlen(a_str);//获取数组长度
len_b=strlen(b_str);//
for(int i=0; i<len_a; i++)
{
a_int[len_a-1-i]=a_str[i]-'0';
}
for(int i=0; i<len_b; i++)
{
b_int[len_b-1-i]=b_str[i]-'0';
}
if(len_b>len_a)//判断结果正负:位数不同
{
swap(len_b,len_a);//交换长度和数值,保证永远大减小
swap(a_int,b_int);
cout<<"-";//确立结果为负数
}
else if(len_b==len_a)//位数相同
{
if(strcmp(a_str,b_str)<0)//注意这里比较的是字符串的字典序
{
swap(len_b,len_a);//交换长度和数值,保证永远大减小
swap(a_int,b_int);//交换数值,而非字符串
cout<<"-";
}
}
len_ans=len_a;//减法的最大结果位数就是被减数位数
for(int i=0; i<len_ans; i++)
{
if(a_int[i]<b_int[i])//判断借位
{
a_int[i]+=10;
a_int[i+1]--;
}
ans[i]=a_int[i]-b_int[i];
}
while(ans[len_ans-1]==0&&len_ans>1)//注意结果为0的情况
{
len_ans--;//直接缩短长度,不需要考虑
}
for(int i=len_ans-1; i>=0; i--)
{
cout<<ans[i];
}
return 0;
}
3.高精度乘低精度
在C++中实现高精度乘以低精度(即大数乘以标准整数)的算法,可以采用类似于手算乘法的方法。以下是实现这一功能的基本思路:
-
输入处理:将高精度数以字符串形式输入,低精度数以整数形式输入。
-
初始化结果:创建一个结果数组,其长度至少与高精度数的位数一样长,用于存储乘法过程中的中间结果。
-
逐位乘法:
- 从最低位开始,将低精度数与高精度数的每一位进行乘法运算。
- 将乘积的每一位(包括进位)加到结果数组的相应位置。
-
进位处理:在每次乘法操作后,需要将进位加到下一次乘法的结果中。
-
结果构建:在完成所有乘法操作后,将结果数组转换为字符串形式,以构建最终的乘法结果。
-
去除前导零:如果结果字符串以零开头,需要去除这些前导零。
-
输出结果:将最终的结果输出或返回。
#include <iostream> #include <cstring> using namespace std; int main() { char a_str[1001] = {}; //存储输入的高精度数 int a_int[1001] = {}; //接收数据并参与计算 int len_a = 0; //高精度数的长度变量 long long ans[1001] = {}; //结果数组 int len_ans = 0; //结果数组长度 int in = 0; //进位变量 int b_int;//参与计算 cin >> a_str >> b_int; //输入高精度数 len_a = strlen(a_str); //获取A的位数 for (int i = 0; i < len_a; i++) //循环转换 { a_int[i] = a_str[len_a - 1 - i] - '0'; //转换A的值 } len_ans = len_a; for (int i = 0; i < len_ans; i++) //判断运算结束 { ans[i] = (a_int[i] * b_int) + in; //计算结果 in = ans[i] / 10; //获取进位 ans[i] %= 10; //去掉进位 } while (in)//最高位进位 { ans[len_ans] = in % 10; in = in / 10; len_ans++; } while (ans[len_ans - 1] == 0 && len_ans > 1)//退位处理 { len_ans--; } for (int i = 0; i < len_ans; i++) //逆序输出结果 { cout << ans[len_ans - 1 - i]; } return 0; }
4.精度乘高精度
在C++中实现高精度乘法(字符串),即两个大数的乘法运算,可以采用类似于手算乘法的方法,但需要处理更长的数字和更多的细节。以下是实现这一功能的基本思路:
-
输入处理:将两个需要相乘的大数以字符串形式输入。
-
字符串反转:为了从最低位开始处理,将两个字符串反转。
-
初始化结果数组:创建一个结果数组,其大小至少为两个输入字符串长度之和,用于存储乘法过程中的中间结果。
-
逐位乘法:
- 从最低位开始,将第一个字符串的每一位与第二个字符串的每一位进行乘法运算。
- 将得到的乘积按照位数放置在结果数组的相应位置,并加上之前乘法可能产生的进位。
-
进位处理:在每次乘法操作后,将进位加到结果数组的下一列。
-
结果累加:在完成所有逐位乘法后,将结果数组中的所有元素相加,这一步类似于加法,但只涉及单个数字的累加。
-
去除前导零:在最终结果构建完成后,如果结果字符串以零开头,需要去除这些前导零。
-
反转结果:由于之前反转了输入的字符串,所以在乘法完成后需要再次反转结果字符串。
-
输出结果:将最终的结果输出或返回。
以下是实现代码:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a_str[1000] = {}, b_str[1000] = {}; //存储高精度数
int a_int[1001] = {}, b_int[1001] = {}; //存储计算数据
int ans[1001] = {}; //存储结果
int len_a, len_b, len_ans = 0; //A,B,ans的位数
int in = 0; //进位变量
cin >> a_str >> b_str; //输入数据
len_a = strlen(a_str); //获取A的位数
len_b = strlen(b_str);
//倒序存储
for (int i = 0; i < len_a; i++)
{
a_int[len_a - 1 - i] = a_str[i] - '0';
}
for (int i = 0; i < len_b; i++)
{
b_int[len_b - i - 1] = b_str[i] - '0';
}
//计算
for (int j = 0; j < len_b; j++) //运算轮次
{
for (int i = 0; i < len_a; i++) //运算次数
{
ans[i + j] = (a_int[i] * b_int[j]) + in + ans[i + j];
in = ans[i + j] / 10; //进位
ans[i + j] %= 10;
}
ans[len_a + j] += in; //每轮次的最高位进位
in = 0; //重置进位变量
}
len_ans = len_a + len_b; //预估结果长度
while (ans[len_ans - 1] == 0 && len_ans > 1)
{
len_ans--;
}
//倒序输出
for (int i = len_ans - 1; i >= 0; i--)
{
cout << ans[i];
}
return 0;
}
在C++中实现高精度除以低精度(即大数除以标准整数)的算法,可以采用类似于手算长除法的方法。以下是实现这一功能的基本思路:
-
输入处理:将高精度数以字符串形式输入,低精度数以整数形式输入。
-
初始化变量:
- 创建一个空字符串用于存储最终的商。
- 创建一个临时字符串用于存储当前处理的子字符串。
-
处理特殊情况:
- 如果高精度数为0或低精度数为0,直接返回商为0或抛出异常。
-
字符串转换:如果需要,将高精度数转换为一个整数数组,以便于处理。
-
逐位除法:
- 从高精度数的最低位开始,逐步构建临时字符串,直到其数值大于或等于低精度数。
- 对临时字符串进行除法运算,得到商的当前位,并将其添加到
quotient
中。 - 从临时字符串中减去除法结果与低精度数的乘积,更新临时字符串为新的子字符串。
-
处理余数:在完成所有除法步骤后,临时字符串中的值即为最终的余数。
-
输出结果:将最终的商和余数(如果需要)输出或返回。
以下示例代码:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a_str[1001] = {}; //存储高精度数据
int a_int[1001] = {}, b; //参与计算
int len_a = 0; //数据长度
int rem = 0; //余数
int ans[1001] = {}; //储存结果
int len_ans = 0; //结果长度
cin >> a_str >> b; //输入数据
len_a = strlen(a_str); //获取A的有效长度
for (int i = 0; i < len_a; i++) //遍历所有位数(逆序)
{
a_int[i] = a_str[i] - '0'; //高位对齐,正序转换
}
len_ans = len_a;
for (int i = 0; i < len_ans; i++) //判断运算是否结束
{
ans[i] = (rem * 10 + a_int[i]) / b; //计算结果
rem = (rem * 10 + a_int[i]) % b;
}
int k = 0;//最高位定位变量
while (ans[k] == 0 && k < len_ans - 1) //判断最高位是否为0
{
k++;//初始位置后移
}
for (int i = k; i < len_ans; i++) //正序循环(整数部分)
{
cout << ans[i]; //输出结果
}
cout <<endl<<rem;//余数输出(如果需要)
return 0;
}
小结
在C++中实现高精度运算(字符串)通常涉及以下几个步骤和关键点:
-
输入处理:将数字以字符串的形式接收,因为字符串可以表示任意长度的数字。
-
字符串反转:在进行加法和乘法操作时,通常需要从最低位开始处理,因此首先将输入的字符串反转。
-
逐位运算:
- 加法:逐位相加,同时考虑进位。
- 减法:逐位相减,如果当前位不够减,则需要从高位借位。
- 乘法:逐位乘以另一个数的每一位,并将结果按位累加。
- 除法:逐位试除,确定商的每一位,并更新余数。
-
进位和借位处理:在加法和乘法中,需要正确处理进位;在减法中,需要正确处理借位。
-
结果构建:在完成逐位运算后,将结果按正确的顺序排列(如果进行了反转,则需要再次反转)。
-
去除前导零:在加法、减法和乘法的结果中,如果存在前导零,需要去除。
-
异常处理:
- 除法操作中,需要处理除数为零的异常情况。
- 减法操作中,如果操作数大小比较复杂,可能需要先进行排序或处理。
-
数据结构选择:在某些实现中,除了使用字符串,还可以使用数组或向量来存储和处理每一位的数值。
-
优化考虑:对于非常大的数字,考虑算法的时间复杂度和空间复杂度,以及可能的优化方法。
-
测试:实现后,需要对各种边界条件和典型情况进行充分的测试,确保算法的准确性和鲁棒性。
-
代码可读性:保持代码的清晰和可读性,使用适当的变量名和注释来解释关键代码段的功能。
-
扩展性:在设计算法时,考虑其扩展性,例如,是否可以容易地添加对更多运算的支持,或者对不同数据类型的支持。
通过遵循这些步骤和关键点,你可以实现一个能够处理任意长度数字的高精度运算库。这些操作在金融、科学计算和大数据处理等领域中非常有用。
谢谢观看~( ̄y▽, ̄)╭
THE END~~~
(有错误或优化方案可以在评论区讨论哦~,不喜勿喷~)