c++中双浮点数出现丢失精度的原因是什么

  介绍

本篇文章给大家分享的是有关c++中双浮点数出现丢失精度的原因是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

在Win32下,把int,指针地址,长等4字节整数赋给一个双后,再用该双数赋给原始类型的数,得到的结果于最初的数值一致,即不存在任何精度丢失。例如下面的结果将总是真的:

, long =123456,,//assign  any  long  number 这里   db, double =一个;   ,long  b=数据库;   ,printf (“% s \ n",==b ?“true":“false");

但是对于很久或win64下的指针地址等8字节整数将存在精度丢失,于是对这方面做了一个简单的测试:

# include   # include      void  showEncodeOfDouble (unsigned  char *, db) {      ,const  int  ByteLength=8,   ,(int  i=ByteLength-1 i>=0;我——),   ,,printf (% .2x",“db[我]);      ,printf (“\ n");      }         int  main () {   ,   ,unsigned  long  long  maxULL=0 xffffffffffffffff;,//2 ^ 64 - 1=18446744073709551615,   ,,,,,,,,,,,,//max  unsigned  long 长   ,printf (“% llu \ n" maxULL);      d1, double =maxULL;,,,,,,,,//20 bit 意义重大,Precision  Loss    ,printf (“% f \ n" d1),,,,,,,      ,maxULL=d1;   ,printf (“% llu \ n" maxULL);   ,   ,showEncodeOfDouble (unsigned  char *), d1);      ,系统(“pause");   ,return  0;   }

输出的结果如下(visual studio, win32):

18446744073709551615
18446744073709552000.000000
9223372036854775808
, 43 f0 00 00 00 00 00 00

至此,有两点疑问(暂时不理会代码中showEncodeOfDouble的结果):

,1)为什么丢失精度后得到的两个数是18446744073709552000.000000 ?
,2)为什么将双数重新转化为无符号很久后得到的数又和双不一致呢?

对于这两个问题,需要对c++浮点数的规格有一定的了解。

<强> 1,IEEE浮点标准

C/C++采用的是IEEE浮点标准,它以“二进制的科学表示法”表示一个小数:

C++中double浮点数出现丢失精度的原因是什么

其中M是一个整数部分仅有一位的二进制小数,例如1.011,表示十进制下的1.375。E表示该小数以2为底时的阶数。基于以上的表示方式,小数需要对三部分进行编码:表示符号的s,及阶码E、尾数码M。C++中的double类型三种编码所占的位数如图所示。

C++中double浮点数出现丢失精度的原因是什么

53位尾数码所能达到的精度为53二进制位,约为16 个十进制位( 53 log10(2) ≈ 15.955) [1],尾数码的编码中还有一个隐含的开头整数位1(或0,当11位阶码全0时)因此实际中可得15-17位十进制的精度。当有效位数最多15位的十进制数转换成double然后重新转换为原来的十进制类型时,数值保持一致;另一方面,将一个double数转化为可以容纳17位以上有效数字的十进制数再重新转化为double,结果数值也保持一致。

这就解释了为什么4字节的整数转化为double重新转化能保持一致(2^32=4294967296仅10个有效位),而8字节的整数却可能丢失精度(2^64-1=18446744073709551615共20个有效位)。但第一个问题中整数丢失精度后转化成的double数值是怎么来的呢,这需要了解C++阶码和尾数对于double数值的意义。

2 阶码编码和尾数编码

在阶码编码中,有一个常数偏置量Bias=1023,假设11位阶码所代表的无符号整数值为e,

1)若e不为0(11位全为1时用于表示特殊数字,此处不讨论),则double数值为

C++中double浮点数出现丢失精度的原因是什么

2)若e=0,则小数值为

C++中double浮点数出现丢失精度的原因是什么 

那么,可以看函数showEncodeOfDouble了,它的作用是将一个double数的编码按字节打印出来(左边是高字节),按其打印结果按照上面计算,可知double编码值表示的数值是2^64,这是合理的,当把精度较高的整数转化为double时,C++采用向偶数舍入的方式得到最接近的值[2]。至于打印出的结果,属于C++浮点数打印中的细节问题。

c++中双浮点数出现丢失精度的原因是什么