今天主要讲一下数学的知识。
一、进制转换:
十进制到k进制:短除法:顺除至0,逆序取余。
k进制转十进制:乘权相加。
常见进制:四进制(对应2位二进制)、八进制(对应3位二进制)、十六进制(对应4位二进制,A表示10,B表示11,...,F表示15)
常见进制在c++中的表示:二进制:前加0b;八进制:前加0;十六进制:前加0x。
小提示:只有十进制下的读数是“...几千几百...”的读法,其他进制都直接把数位上的数读出来就行辣。
二、高精度
常见数据类型的范围:int:[-232,232-1]
long long :[-263,263-1]≈1020
那么对于超过这些数据范围的数怎么办呢?(我才不说有个int_128) ,这时候就要用到高精度了。高精度就是用来解决大整数的运算。
有关高精度加减乘除的基本讲解可见我的另一篇博客,这里只说说新的东西。
https://www.cnblogs.com/InductiveSorting-QYF/p/10679946.html(博客地址)
对于高精度,我们可以写好高精度重载运算符的模板,码程序时先用int型码好程序,用小数验证算法正确性后再将int改成高精型(结构体的运用),否则程序出错后难以判断出错在算法还是高精。对于初始化结构体,可用构造函数(面向对象的知识),简单来说就是一个不写类型、函数名为结构体类型名、写在结构体里的函数,该函数每当有该结构体对象声明时都会被调用一次。(与此对应的还有析构函数,有兴趣的OIER可以看看:https://www.runoob.com/cplusplus/cpp-constructor-destructor.html(C++ 类构造函数 & 析构函数
) 配合C++中struct和class的区别 食用更佳)
代码如下:
1 struct gaojing 2 { 3 int z[100010]; 4 int l; 5 gaojing() 6 { 7 l=1; 8 memset(z,0,sizeof(z)); 9 } 10 }
重载运算符(以加号为例)代码:
1 gaojing operator+(gaojing a,gaojing b) 2 { 3 gaojing c; 4 5 int l = max(a.l,b.l); 6 for (int i=0;i<l;i++) 7 { 8 c.z[i] += a.z[i] + b.z[i]; 9 c.z[i+1] += c.z[i] / 10; 10 c.z[i] = c.z[i] % 10; 11 } 12 if (c.z[l] != 0) l++; 13 c.l = l; 14 15 return c; 16 }
细心的同学会发现,其实这个有个问题。想必大家都知道函数传值调用与传址调用的区别:传值调用不会改变主调用函数中变量的值,而传址调用则会改变。同时由此发现每次传值调用都会拷贝一份主调用函数的变量。这个变量小的话还好,但如果要是很大的数组的话,必然会增加额外的时间复杂度,而且一个程序的加法运算又很多,那么调用函数的次数也很多,总的一看,时间就被浪费许多了。
怎么处理这种情况?
既然传值调用不行,传址调用就好了嘛。同时为了防止打码手抖改掉加数的值,可在形参表中加上const。正确代码如下:
1 gaojing operator+(const gaojing &a,const gaojing &b) 2 { 3 gaojing c; 4 5 int l = max(a.l,b.l); 6 for (int i=0;i<l;i++) 7 { 8 c.z[i] += a.z[i] + b.z[i]; 9 c.z[i+1] += c.z[i] / 10; 10 c.z[i] = c.z[i] % 10; 11 } 12 if (c.z[l] != 0) l++; 13 c.l = l; 14 15 return c; 16 }
其他的运算符重载大都与此相差不大。这里再说明一下输入输出的重载:
代码如下:
1 struct gaojing 2 { 3 int z[100010]; 4 int l; 5 6 friend istream& operator>>(istream &cin, gaojing &a) 7 { 8 static char s[100010]; 9 cin >> s; 10 int l=strlen(s); 11 for (int i=0;i<l;i++) 12 a.z[i] = s[l-i-1] - '0'; 13 a.l = l; 14 15 return cin; 16 } 17 18 friend ostream& operator<<(ostream &cout,const gaojing &a) 19 { 20 for (int i=a.l-1;i>=0;i--) 21 cout << a.z[i]; 22 23 return cout; 24 } 25 };
输入/出的重载有点特别。它们需要写在struct的定义中。(好像因为是友联函数什么的,就是那个friend啦。),而且重载的是“<<”和">>"。istream和ostream是输入和输出流,函数形参表的意思差不多是:将cin里的数读到a中;将a里的数输出到cout中。只能是cin和cout,不能scanf和printf。(百度警告)。重载完各种运算符后,就可以把int型扔掉了,写程序真方便(高精模板真多)
最后TIP:以上提及的四则运算符都没有考虑有负数出现的情况,有负数需另考虑。