C++高精度实数类实现[0]

来源:互联网 发布:远行星号舰船数据 编辑:程序博客网 时间:2024/05/16 06:35

自学C++也有近一个月了,中途研究了一段时间MFC,感觉挺难得。想了想还是先把基础学好,不要好高骛远吧~吐舌头

于是乎俺决定自己写一个C++的高精度实数类,乍一想貌似比较容易咔咔大笑

以前在Java里用过 BigInteger 和 BigDecimal 这样的基于字符串实现的大整数、高精度小数的类。我希望自己能编写一个类似实现的C++类。

由于整数也是小数的一种,我就偷个懒,直接写高精度实数类好啦奋斗


类名就叫 d_BigDecimal 了,看似有点不伦不类哈~这个d就是俺名字的首字母咯偷笑

我设想的这个类对外提供一个构造函数,接收一个C风格字符串(const char*)来构造指定实数。之所以不使用C++提供的string类,算是个人的小脾气吧(不用你们的类库俺也能做得好~鄙视


下面是很重要的一步了,内部数据如何存储?这直接关系到运行时的效率。由于该类是很基础的一个类,我想尽可能的让运算效率提高~此处得动动脑子了疑问

可惜的是,我一没学过数据结构,二没学过算法分析,只能凭空乱想啦~~~

以下内容纯属个人浅见,不对勿喷哦尴尬


很显然,如果在内部存储时不做任何处理,直接利用构造函数中传递进来的字符数组,然后以10进制的加减乘除做运算,效率是极其低下的,其中涉及到进位尤其麻烦。我第一个排除了这种想法。

用2进制存储或许是个好主意。首先,2进制数的加法虽然也有进位,但是情况简单,便于处理,这对降低编写代码的复杂度有所帮助。当然,更重要的一个理由是,我认为2进制的乘除运算比10进制在运行效率上要高得多。


举一个例子:

10进制中

19.625  和 23.375

这两个数的2进制形式分别是

10011.101 和 10111.011

做乘法运算,当然先忽略小数点

19625 * 23375

-> 19625 * 5 -> 5 * 5 -> 25 * 1 -> 25

                     -> 2 * 5 -> 10 * 10 -> 100
                     -> 6 * 5 -> 30 * 100 -> 3000
                     -> 9 * 5 -> 45 * 1000 -> 45000
                     -> 1 * 5 -> 5 * 10000 -> 50000

                                  -> 25 + 100 + 3000 + 45000 + 50000 -> 98125

                                  -> 98125 * 1 -> 98125

-> 19625 * 7 ->……

                     ->……
                     ->……
                     ->……
                     ->……
                     ->……
                     ->……

                                  -> 137375 * 10 -> 1373750

-> 19625 * ->……
-> 19625 * ->……
-> 19625 * ->……

-> 458734375


大约进行了100次加法运算才得到结果(忽略小数点),这其中还默许了10以内的数相乘结果直接由程序提前穷举给出,否则计算量更大


在看看2进制下的运算呢?

10011101 * 10111011

        -> 100111011 ->10011101 * 1 -> 10011101

        -> 10011101 * 1 -> 10011101 * 10 -> 100111010

        -> 10011101 * 0 -> 0

        -> 10011101 * 1 -> 10011101 * 1000-> 10011101000
        -> 
10011101 * 1 -> 10011101 * 10000-> 100111010000
        -> 
10011101 * 1 -> 10011101 * 100000-> 1001110100000
        -> 
10011101 * 0 -> 0
        -> 
10011101 * 1 -> 10011101 * 10000000-> 100111010000000

-> 10011101 + 100111010 + 10011101000 + 100111010000 + 1001110100000 + 100111010000000

-> 111001010101111

仅仅23次运算就得出了结果(忽略小数点),并且不需要像10进制乘法一样给出乘法表。其中优劣显而易见。得意


决定用2进制形式存储数据了,自然而然就会想到用一个存放了一串0、1的数组来实现咯~嗯,还需要一个变量表示小数点所在位数大笑


比如用户输入"19.625"(2进制10011.101),我们在内部就有一个这样的数组对应 {1, 0, 1, 1, 1, 0, 0, 1, 0}

注意,这里是从低位开始往高位排序的,最高位表示符号位,0是整数1是负数(好吧,我承认抄袭了原码补码的那一套偷笑),然后小数点所在位数是3。这样,一个高精度的实数就被我们表示出来啦~


写到这里,突然发现一个小问题呀,哎,不写BigInteger直接写BigDecimal果然有一点不好……这个表示小数点所在位数的变量似乎限制了我们的精度,就算用unsinged long来存储这个变量,也只能表示小数点后2^32-1位小数额。如果提前写好了BigInteger,那就没有限制啦~

不过这么一点点小问题也无所谓了~写完以后再修改也很容易。况且……2^32-1位小数也够用啦!


那么,这个存储2进制数的数组用什么类型呢?int给人的感觉太大了,毕竟只需要0和1两个变量就可以了。short呢?或许是个好主意,难道没有更短的了吗?

当然有,bool就是~

一个bool型数据在内存中占1字节,short占2字节,int是4字节。我们的高精度数需要大量存储这样的数据,当然是越小越好咯。当然,char也是一个不错的选择,它在内存中也仅占1字节。但从另一个角度考虑,bool只有两种状态,在我们采用2进制存储的前提下,更为方便!


于是,我们终于确定了d_BigDecimal的两个成员变量:

bool decimal_bin[];unsigned long point_index;

接下来的问题就是,如何在构造函数中将用户传入的以10进制表示的字符串数字转化为我们内存中的数据了。

写了这么久,也有点累了,剩下的下次再讨论吧~~~吐舌头


原创粉丝点击