详解C/C++高精度算法的简单实现
目录
- 前言
- 一、基本原理
- 二、辅助方法
- 1、字符串转高精度
- 2、整型转高精度
- 3、比较
- 4、打印
- 三、算法实现
- 1、加法
- 2、减法
- 3、乘法
- 4、除法
- 四、使用示例
- 1、加法
- 2、减法
- 3、乘法
- 4、除法
- 总结
前言
由于上一章《C/C++ 高精度(加减乘除)算法实现》是基于工程项目考虑实现的,也做了一定的优化,实现过程较为复杂。不利于移植和使用,且比较难以理解,时间一长代码也容易忘记,所以重新编写了一个简化的版本,方便以后需要时拷贝使用。
一、基本原理
1、存储方式
采用数字记录高精度数字,数组的第一个元素存储数据长度,比如记录数字为1024示例如下:
2、计算方式
采用模拟立竖式计算,比如加法的计算流程,如下图所示1024+9000:
这里只给出加法的计算说明,其他的以此类推,减法与加法基本一致。乘法和除法略有不同,通过示例图表示也复杂,还不如通过代码去理解,本质的方法就是模拟笔算的立竖式计算。
二、辅助方法
1、字符串转高精度
长度记录在数组第一个元素中
/// <summary> /// 通过字符串初始化 /// </summary> /// <param name="a">[in]高精度数组</param> /// <param name="value">[in]字符串首地址</param> static void loadStr(int* a,const char* value) { //记录长度 a[0] 编程客栈= strlen(value); for (int i = 1; i <= a[0]; i++) a[i] = value[a[0] - i] - '0'; }
2、整型转高精度
/// <summary> /// 通过无符号整型初始化 /// </summary> /// <param name="a">[in]高精度数组</param> /// <param name="value">[in]整型值</param> static void loadInt(int* a, uint64_t value) { for (size_t i = 1; i < 8096; i++) { a[i] = value % 10; value /= 10; if (!value) { //记录长度 a[0] = i; return; } } }
3、比较
/// <summary> /// 比较两个高精度数的大小 /// </summary> /// <param name="a">[in]第一个数</param> /// <param name="b">[in]第二个数</param> /// <returns>1是a>b,0是a==b,-1是a<b</returns> static int compare(int* a, int* b) { if (a[0] > b[0])return 1; if (a[0] < b[0])return -1; for (int i = a[0]; i > 0; i--) if (a[i] > b[i])return 1; else if (a[i] < b[i])return -1; return 0; }
4、打印
/// <summary> /// 打印输出结果 /// </summary> static void print(int* a) { if (!a[0]) printf("0"); for (int i = a[0]; i > 0; i--) printf("%d", a[i]); }
三、算法实现
原理就不做具体介绍了,四种计算的核心都是模拟立竖式计算。
1、加法
为了保证代码相对简单,当b长度较小时可能会做一些多余的计算,不影响结果。
/// <summary> /// 加法(累加) ///结果会保存在a中 /// </summary> /// <param name="a">[in]被加数</param> /// <param name="b">[in]加数</param> static void acc(int* a, int* b) { int len = a[0] > b[0] ? a[0] : b[0]; memset(a + a[0] + 1, 0, (len - a[0] + 1) * sizeof(int)); memset(b + b[0] + 1, 0, (len - b[0] + 1) * sizeof(int)); for (int i = 1; i <= len; i++) { int temp = a[i] + b[i]; a[i] = temp % 10; a[i + 1] += temp / 10; } if (a[len + 1])a[0]++; }
2、减法
/// <summary> /// 减法(累减) ///结果会保存在a中 /// </summary> /// <param name="a">[in]被减数,被减数必须大于等于减数</param> /// <param name="b">[in]减数</param> static void subc(int* a, int* b) { memset(b + b[0] + 1, 0, (a[0] - b[0]) * sizeof(int)); for (int i = 1; i <= a[0]; i++) { int temp = a[i] - b[i]; a[i] = temp; if (temp < 0) { //借位 a[i + 1] -= 1; a[i] += 10; } } //记录长度 for (int i = a[0]; i > 0; i--) if (a[i]) { a[0] = i; return; } a[0] = 0; }
3、乘法
/// <summary> /// 乘法 /// </summary> /// <param name="a">[in]被乘数</param> /// <param name="b">[in]乘数</param> /// <param name="c">[out]结果开发者_Go培训,数组长度必须大于等于aLen+bLen+1</param> static void mul(int* a, int* b, int c[]) { c[a[0] + b[0]] = 0; memset(c, 0, sizeof(int) * (a[0] + b[0] + 1)); for (int i = 1; i <= a[0]; i++) { int j; int d = 0; //被乘数的一位去乘以乘数的每一位 for (j = 1; j <= b[0]; j++) { int temp = a[i] * b[j] + c[j + i - 1] + d; c[j + i - 1] = temp % 10; d = temp / 10; } if (d) { c[j + i - 1] = d; } } //记录长度 for (int i = a[0] + b[0]; i > 0; i--) if (c[i]) { c[0] = i; return; } }
4、除法
采用了升阶+减法实现
/// <summary> /// 除法 /// 依赖减法subc /// </summary> /// <param name="a">[in]被除数,被除数必须大于除数</param> /// <param name="b">[in]除数</param> /// <param name="c">[out]商,数组长度大于等于aLen-bLen+1</param> /// <param name="mod">[out]余数,数组长度大于等于aLen</param>> /// <param name="temp">[in]临时缓冲区,由外部提供以提高性能,数组长度大于等于aLen-bLen+1</param> static void divi(int* a, int* b, int* c, int* mod, int* temp) { //相差的阶数 int digit = a[0] - b[0] + 1; memcpy(mod, a, (a[0] + 1) * sizeof(int)); memset(c, 0, sizeof(int) * (digit + 1)); memset(temp, 0, sizeof(int) * digit); androidwhile (digit) { //升阶 memcpy(temp + digit, b + 1, sizeof(int) * b[0]); temp[0] = b[0] + digit - 1; //减法 while (compare(mod, temp) != -1) { subc(mod, temp); c[digit]++; } digit--; } //记录长度 for (int i = a[0] - b[0] + 1; i > 0; i--) if (c[i]) { c[0] = i; return; } }
四、使用示例
1、加法
计算累加
int main() { int64_t n; int num[1024]; int num2[1024]; std::cin >> n;OITJfr loadInt(num, 0); for (int64_t i = 1; i <= n; i++) { loadInt(num2, i); acc(num, num2); } print(num); return 0; }
结果:
2、减法
两个任意n位数的减法,数字1大于数字2。
intandroid main() { int a1[8096], a2[8096]; std::string s1, s2; std::cin >> s1 >> s2; loadStr(a1, s1.c_str()); loadStr(a2, s2.c_str()); subc(a1, a2); print(a1); return 0; }
结果:
#数字1
752425289999999999999652142141414141414146666676667677682324000001302461646520#数字2587891851201874512000000000154515100202121555555555555555555555545477910232111#计算结果164533438798125487999652141986899041212025111121112122126768444455824551414409
3、乘法
计算阶乘
int main() { int64_t n; int num[8192]; int num2[8192]; int num3[8192]; int* p1 = num; int* p2 = num3; std::cin >> n; loadInt(num, 1); for (int64_t i = 1; i <= n; i++) { loadInt(num2, i); mul(p1, num2, p2); int* temp = p1; p1 = p2; p2 = temp; } print(p1); return 0; }
结果:
#阶乘数
1000#计算结果4023872600770937735437024339230039857193748642107146325437999104299385123986290205920442084869694048004799886101971960586316668729948085589013238296699445909974245040870737599188236277271887325197795059509952761208749754624970436014182780946464962910563938874378864873371191810458257836478499770124766328898359557354325131853239584630755574091142624174743493475534286465766116677973966688202912073791438537195882498081268678383745597317461360853795345242215865932019280908782973084313928444032812315586110369768013573042161687476096758713483120254785893207671691324484262361314125087802080002616831510273418279777047846358681701643650241536913982812648102130927612448963599287051149649754199093422215668325720808213331861168115536158365469840467089756029009505376164758477284218896796462449451607653534081989013854424879849599533191017233555566021394503997362807501378376153071277619268490343526252000158885351473316117021039681759215109077880193931781141945452572238655414610628921879602238389714760885062768629671466746975629112340824392081601537808898编程客栈93964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
4、除法
给定两个非负整数A,B,请你计算 A / B的商和余数。
int main() { int a1[8096], a2[8096], c[8096], mod[8096], temp[8096]; std::string s1, s2; std::cin >> s1 >> s2; loadStr(a1, s1.c_str()); loadStr(a2, s2.c_str()); divi(a1, a2, c, mod, temp); print(c); std::cout << std::endl; print(mod); return 0; }
结果:
#被除数
12458848948151231366666666666666665454545123156415641561231561213648#除数88484851521548496564154848456486789#商140802055198308817458997123299946#余数25178368711335236611547594127800254
总结
以上就是今天要讲的内容,本文提供的是较为简化的实现,且每个方法基本是独立的,可单独拿来使用,用法也比较简单,由于采用数组第一个元素存储长度,接口就变得很简洁,使用起来也方便了很多。
到此这篇关于详解C/C++高精度算法的简单实现的文章就介绍到这了,更多相关C/C++高精度算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
精彩评论