Double类型数据造成的数据精度丢失
本文最后更新于 2024年6月7日 下午
这是由一道简单的蓝桥杯例题所得出的小经验,这道题目的主要内容是取一个数小数点后的某几位数字。
首先我想到,要取小数点后的n位数字,只要我将数小数点后的数字其乘以10的n次方,得到的整数部分不就是所求的数字吗?
于是我使用了这样的方式在 C++ 中计算:
1 |
|
但最后验证结果却显示我的结果不正确,我与一份正确的代码进行对比,发现除了求阶乘部分不一样外,我们的代码是完全一样的。那么完全正确的代码中是如何求阶乘的呢?
1 |
|
那么为什么会出现,两种不同的求阶乘方式,最后的结果却不一样的现象呢?
具体的原因还要和浮点数在计算机中的存储方式有关,我们知道计算机通用以IEEE754标准存储浮点数,浮点数分为“单精度”与“双精度”两种。计算机也将我们人类世界的浮点数转化为这以两种形式表示。
浮点数 n 表示为:
1 |
|
其中 S 、M 、E都为二进制数
S为符号,M为尾数,E为阶码
双精度中S为1位,E为11位,M为52位
单精度中S为1位,E为8位,M为23位
浮点数的存储结构如下:
由低到高分别为符号、阶码、尾数,这是一种类似于科学计数法的表示方式,我们知道计算机中的数都是以二进制进行保存的,所以将复数转化为这种形式,便于存储于计算机中。
但这样也是有局限性的,因为计算机的存储数字位数有限,所以这种数字表示的离散的,但显示世界中的数字是连续的,这就造成并不是所有的数字都可以表示在计算机中,这就造成了浮点数表示的误差。
举个例子来说
1 |
|
这个数转换为科学计数法为
1 |
|
可以发现,如果我小数点后只能容纳23位,但转换为科学计数法后却有26位,没办法只能将最后的数字舍掉了。这就造成了误差。
OK!让我们再来看一下pow
函数原型
1 |
|
可以看到pow
函数的形式参数的类型为double
,所以在传入任何类型的实参都会将其转化为double
类型,也就是说传参的过程中一旦参数过大一定会出现精度丢失的情况。这就是为什么pow
函数精度丢失的原因。