C语言-浮点类型

C语言-浮点类型

浮点类型

C语言-浮点类型

在0的两侧有一小块区域,这个区域非常接近0,但是不等于0,是float(表达范围数量级10^-38^)或者double(达范围数量级10^-308^)无法表达的,而0是可以表达的;nan:不是一个有效的数字。有效数字:在有效数字范围是精确的,超出这个范围是不准确的。

C语言-浮点类型

%e:输出科学计数法的形式,%E只是表示时字母大写。

在使用科学计数法时,数字与E或者e之间不要有任何空格。小数点位数较多时,double有时显示不出来小数位的数字如1E-10,以double输出时只是0.000000,想要看到1,在printf可以指定输出的位数,如使用%.16f。所以可以在%和f之间加上.n可以指定输出小数点后几位,这样的输出时做四舍六入五成双的规则。

printf("%.3f\n",-0.0049) 结果保留3位 -> 0.005

printf("%.30f\n",-0.0049) 结果保留30位 -> 0.004899999999...

printf("%.3f\n",-0.00049) 结果保留3位 -> 0.000

printf("%.3f\n",-0.0045) 结果保留3位 -> 0.0004

第二种实际上是计算机内部真实的情况,-0.0049实际不能被计算机精确的表达为-0.0049。

虽然理论上来说数是连续的,也就是说,任意取两个点,你可以在两个点之间获得任意多的数,数量是无限的(实数的稠密性),但对计算机来说,只能用离散的数字来表达数字,位于两个紧邻的数字之前的数字是数据类型如double,不能表达的。当你写出0.0049的时候,而这个数恰好是所能表达的两个数之间的数字,我们就必须选择离它最近的那个数字来表达它,但它和实际的0.0049是有段距离的,而这个距离就是浮点数误差。

第四种里的0.0045其实是0.00449... ,是个很接近0.0045的数字

浮点数的范围与精度

超过范围的浮点数

printf输出inf表示超过范围的浮点数:+- ∞

printf输出nan表示不存在的浮点数

浮点正数除以0结果是正inf;浮点负数除以0结果为-inf,浮点0除以0是nan。

但需注意:整数除以0,结果报错。因为无穷大无法用整数来表达,但无穷大可以用浮点数来表达,虽然浮点有效范围内部包含无穷大,但是在浮点数的设计里,把无穷大,nan定义在浮点数里面。同时注意浮点的运算是没有精度的。做个简单的实验:

#include <stdio.h>
int main()
{
    float a,b,c;
    a = 1.345f;
    //f表示一个float型浮点数,不带的话,C默认浮点数类型是double类型
    b = 1.123f;
    c = a + b;
    if (c == 2.468)
        printf("相等\n");
    else
        printf("不相等!c=%.10f,或%f\n",c,c);
    return 0;
}
//结果:不相等!c=2.4679999352(实际只有7位有效2.467999),或2.468000

这里虽然前面声明了float类型,但是在下面表示float也要加上f,否则报错

  • 带小数点的字面量是double而非float
  • float需要用f或F后缀来表明身份
  • 两个float直接用==来判断可能失败
  • fabs(f1-f2) < 1e-8或1e-12(7个有效数字就可以)来判断是否相等。所以不要用浮点数来做一些精确的运算。特别是金钱的运算,例如1.23元和1.34元相加减等,这些误差会累积,解决的简单方法是换算成整数再运算,整数永远都是精确的,所以可以把1.23元换成123分。浮点数只能在一定的范围内相信它。

浮点数的内部表达

整数是纯二进制来表达的,所以两个浮点数可以直接做运算,而浮点数则不同,其背部是一种编码的形式。

C语言-浮点类型

一个bit来表达正负数,11个bit来表达指数部分是多少,后面用来表达分数部分是多少,但这里未必把所有的bit都用完。

浮点数在计算时是由专用的硬件部分(协处理器,现在基本都集成到CPU中了)来实现的,计算时将编码交给专门的硬件,硬件会把其解开来,然后来计算,计算后再编码成这样的数字给你。计算double和float所用的部件是一样的。

选择浮点类型

  • 如果没有特殊需要,只使用double
  • 现代CPU能直接对double做硬件运算,性能不会比float差,在64位的机器上,数据存储的速度也不比float慢。

相关推荐