我们经常使用C语言来计算算式,甚至直接使用它来设计计算器。在这个过程中,不可避免的遇到一个问题,就是C语言数据类型对计算的限制。我们知道float类型是有一个精确度的,并不是有多少个小数位都能精确计算;即便换成double类型,也只能说精确度提升了,但仍然不能说完全准确。很多人怕麻烦,干脆所有小数都尽量扩大成整型计算。但整型Int有一个数据范围大小,太大的数字无法处理。所以基于字符的计算应运而生,它是把数字以字符串的形式存放,处理后的结果也是字符串,以字符串为载体进行运算。而字符串的长度,是可以定义的,理论上只要内存够用,定义多少都不碍事。所以基于字符的计算器解决了C语言基本数据类型对计算的限制。
那么究竟如何设计程序,实现字符的基本运算(加,减,乘,除)呢?
回想小学时候计算加法,那时候没有计算器,是使用竖式计算的。把两个操作数写在纸上,然后按位相加,超10进位。如果是整数,把两个操作数从最低位对齐相加。但如果是小数,那需要把两个操作数从小数点对齐。特别的,如果是减法的话,只能大数字减去小数字,其他形式都要处理成这样才能算。如果是乘法和除法,需要先把小数位去掉,计算好的结果再加上小数位。足以可见,真正令人头疼的不是计算数位,而是不同情况下字符串的对齐处理。其中还要考虑正负号。
为了方便处理,我们必须把一个操作数规范起来。用一个结构体opa_num表示它。一个具体的数字,比如"-123.456",需要被切割成opa_num的各个成员,才方便以后处理。
typedef struct opa_num
{
char sign; //操作数正负号
char int_num[OPA_NUM_LEN]; //操作数整数部分
char float_num[OPA_NUM_LEN]; //操作数小数部分
char num_no_point[OPA_NUM_LEN*2]; //不带小数点的操作数
int index_point; //小数点在操作数中的位置
}opa_num;
此外,我们还需要对数字的字符串制定一些规范。并且还要实现一个函数,对数字字符串进行"规范化"处理。
1.正数不带符号前缀,比如"123.456"。负数带符号前缀,"-123.456"
2.不能有无效的0.比如"001203.045600",标红的字符不合法,应该去除。
3.不允许存在空格等其他无意义的字符。
设计一个函数,用于把字符串处理成这个结构体变量。这样做之后,我们以后就使用这个结构体变量进行计算操作。
void num_split(char *num_str,opa_num* st_opa_num)
用这个结构体变量就要好操作得多了。正负号、整数小数一目了然。使用这样的变量有利于之后进行程序设计。
首先要设计两个数值比较大小的函数。两个数比较大小,先比整数再比小数。从高位向低位比。等于返回0,小于返回-1,大于返回1。
int num_compare(opa_num* st_opa_num1, opa_num* st_opa_num2)