本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第1章,建议3-3:,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
在上面的建议3-1与建议3-2中,已经明确阐述,由于计算机的字长有限,浮点数能够精确表示的数是有限的。因此,在c语言中使用float或者double类型来存储小数是不能得到精确值的。虽然在建议3-2的最后提出使用整数的方法来解决浮点数的精确计算问题,但这种方案不具备代表性和通用性。因此,本建议将向你介绍第二种精确表示浮点数的解决方法,即用分数来表示浮点数。
对于一个浮点数,我们可以简单地把它分解成整数和纯小数两个部分来分开表示。比如浮点数据10.234,它的整数部分是10,纯小数部分是0.234。而对于纯小数部分,受计算机字长的限制,存储时会因为舍入规则而导致失去精确性。因此,这个时候就可以将纯小数部分使用分数来表示。比如,对于有限小数,我们可以这样来表示:

由此,我们可以很简单地推导出它的表示形式。对于有限小数x=0.a1a2…an(其中,a1,a2,…,an为0~9之间的数字),它的分数表示形式如下:
https://yqfile.alicdn.com/f0884c7fe939f7fcbb14aff4bd04fad29f0c29e0.png" >
上面阐述了有限小数的表示形式,但对于无限循环小数如何表示呢?
其实仍然可以使用上面的这种形式来表示。但无限循环小数比有限小数多了一个循环部分,因此我们可以用如下方式来表示:
https://yqfile.alicdn.com/c985f31bb7de7773e18487acb223a3b6a3bc905f.png" >
其中,(3)表示循环体。即,对于无限循环小数x=0.a1a2…an(b1b2…bm)(其中,a1,a2,…,an与b1,b2,…,bm都是0~9的数字,a1a2…an表示非循环部分,括号部分(b1b2…bm)表示循环部分),它的表现形式如下:
至于循环部分(b1b2…bm),我们可以这样处理,即令y=0.b1b2…bm,那么:
将y代入x,即:
也就是:
例如,对于小数0.3(3),根据上述方法转化为分数应为:
下面,我们通过一个示例程序演示一下如何在c语言程序中使用这种表达方式将浮点数表示为分数形式。值得注意的是,这里的精度只能达到long int类型,再大就会发生溢出。如代码清单1-20所示。
代码清单1-20的运行结果如图1-32所示。
在图1-32中,通过分数的形式表示浮点数,从而避免浮点数因为舍入误差而导致的不精确性问题。有兴趣的朋友可以在这个示例代码的基础继续深入研究,从而使该方案能够用于实际的开发环境中。
https://yqfile.alicdn.com/ebb3663a8c1fd4f088d9be6a9380b73c8d892001.png" >