• C语言浮点数


    一、浮点数的概念

    浮点数也称小数或实数。例如,0.0、75.0、4.023、0.27、-937.198 都是合法的小数。

    C语言中采用float和double关键字来定义小数,float称为单精度浮点型,double称为双精度浮点型,long double更长的双精度浮点型。

    在任何区间内(如1.0 到 2.0 之间)都存在无穷多个实数,计算机的浮点数不能表示区间内所有的值。

    二、点用内存的情况

    我们先来测试一下float、double和long double三种浮点数据类型占用内存的字节数。

    示例(book71.c)

    /*
     * 程序名:book71.c,此程序测试float、double和long double占用内存的字节数
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    
    int main()
    {
      printf("sizeof float is %d
    ",sizeof(float));
      printf("sizeof double is %d
    ",sizeof(double));
      printf("sizeof long double is %d
    ",sizeof(long double));
    }
    

    运行效果

    在这里插入图片描述

    三、浮点数的精度

    C标准规定,float类型必须至少能表示6位有效数字,且取值范围至少是10-37~10+37

    double类型和 float类型的最小取值范围相同,但至少必须能表示10位有效数字。

    long double,以满足比double类型更高的精度要求。不过,C只保证long double类型至少与double类型的精度相同。

    看了上面这段文字,估计大家有点晕,在之前的整数章节中,long比int的占用的内存多,存放数据的值也就越大,并且有一个准确的范围,但是,为什么各种浮点数存放数据的值怎么就这么模糊呢?我先不解释原因,浮点数的存储方式比较复杂,暂时不讨论,先用几个程序来测试一下它们的特征。

    1、测试float类型

    示例(book73.c)

    /*
     * 程序名:book73.c,此程序测试float的特征
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    
    int main()
    {
      float ff2=9.9;   // 测试2位的浮点数
      printf("ff2=%f
    ",ff2);
      if (ff2==9.9) printf("ff2==9.9
    ");
    
      float ff5=99.999;   // 测试5位的浮点数
      printf("ff5=%f
    ",ff5);
      if (ff5==99.999) printf("ff5==99.999
    ");
    
      float ff6=999.999;   // 测试6位的浮点数
      printf("ff6=%f
    ",ff6);
      if (ff6==999.999) printf("ff6==999.999
    ");
    
      float ff7=9999.999;   // 测试7位的浮点数
      printf("ff7=%f
    ",ff7);
      if (ff7==9999.999) printf("ff7==9999.999
    ");
    
      float ff8=99999.999;   // 测试8位的浮点数
      printf("ff8=%f
    ",ff8);
      if (ff8==99999.999) printf("ff8==99999.999
    ");
    }
    

    运行效果

    在这里插入图片描述

    从程序的运行我们可以看出float数的两个特征:

    1)float数据类型表达的是一个近似的数,不是准确的,小数点后的n位有误差,浮点数的位数越大,误差越大,到8位的时候,误差了1,基本上不能用了。

    2)用“==”可以比较两个整数或字符是否相等,但是,看起来相等的两个浮点数,就是不会相等。

    2、测试double类型

    示例(book74.c)

    /*
     * 程序名:book74.c,此程序测试double的特征
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    
    int main()
    {
      double ff2=9.9;   // 测试2位的浮点数
      printf("ff2=%lf
    ",ff2);
      if (ff2==9.9) printf("ff2与9.9相等。
    ");
    
      double ff12=999999999.99;   // 测试12位的浮点数
      printf("ff12=%lf
    ",ff12);
      if (ff12==999999999.99) printf("ff12与999999999.999相等。
    ");
    
      double ff13=9999999999.99;   // 测试13位的浮点数
      printf("ff13=%lf
    ",ff13);
      if (ff13==9999999999.99) printf("ff13与9999999999.999相等。
    ");
    
      double ff14=99999999999.99;   // 测试14位的浮点数
      printf("ff14=%lf
    ",ff14);
      if (ff14==99999999999.99) printf("ff14与99999999999.999相等。
    ");
    
      double ff15=999999999999.99;   // 测试15位的浮点数
      printf("ff15=%lf
    ",ff15);
      if (ff15==999999999999.99) printf("ff15与999999999999.999相等。
    ");
    
      double ff16=9999999999999.99;   // 测试16位的浮点数
      printf("ff16=%lf
    ",ff16);
      if (ff16==9999999999999.99) printf("ff16与9999999999999.999相等。
    ");
    
      double ff17=99999999999999.99;   // 测试17位的浮点数
      printf("ff17=%lf
    ",ff17);
      if (ff17==99999999999999.99) printf("ff17与99999999999999.999相等。
    ");
    
      double ff18=999999999999999.99;   // 测试17位的浮点数
      printf("ff18=%lf
    ",ff18);
      if (ff18==999999999999999.99) printf("ff17与99999999999999.999相等。
    ");
    }
    

    运行效果

    在这里插入图片描述

    从程序的运行我们可以看出double数的两个特征:

    1)double数据类型表达的也是一个近似的数,不是准确的,小数点后的n位有误差,浮点数的位数越大,误差越大,到17位的时候,误差了1,基本上不能用了。

    2)用“==”可以比较两个double数值是否相等。

    3、测试long double类型

    示例(book75.c)

    /*
     * 程序名:book75.c,此程序测试long double的特征
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h> 
    
    int main()
    {
      long double ff2=9.9;   // 测试2位的浮点数
      printf("ff2=%Lf
    ",ff2);
      if (ff2==9.9) printf("ff2与9.9相等。
    ");
    
      long double ff12=999999999.99;   // 测试12位的浮点数
      printf("ff12=%Lf
    ",ff12);
      if (ff12==999999999.99) printf("ff12与999999999.999相等。
    ");
    
      long double ff13=9999999999.99;   // 测试13位的浮点数
      printf("ff13=%Lf
    ",ff13);
      if (ff13==9999999999.99) printf("ff13与9999999999.999相等。
    ");
    
      long double ff14=99999999999.99;   // 测试14位的浮点数
      printf("ff14=%Lf
    ",ff14);
      if (ff14==99999999999.99) printf("ff14与99999999999.999相等。
    ");
    
      long double ff15=999999999999.99;   // 测试15位的浮点数
      printf("ff15=%Lf
    ",ff15);
      if (ff15==999999999999.99) printf("ff15与999999999999.999相等。
    ");
    
      long double ff16=9999999999999.99;   // 测试16位的浮点数
      printf("ff16=%Lf
    ",ff16);
      if (ff16==9999999999999.99) printf("ff16与9999999999999.999相等。
    ");
    
      long double ff17=99999999999999.99;   // 测试17位的浮点数
      printf("ff17=%Lf
    ",ff17);
      if (ff17==99999999999999.99) printf("ff17与99999999999999.999相等。
    ");
    
      long double ff18=999999999999999.99;   // 测试17位的浮点数
      printf("ff18=%Lf
    ",ff18);
      if (ff18==999999999999999.99) printf("ff17与99999999999999.999相等。
    ");
    }
    

    运行效果

    在这里插入图片描述

    long double的测试结果与double相同。

    4、测试总结

    float只能表达6-7位的有效数字,不能用“==”判断两个数字是否相等。

    double能表达15-16位有效的数字,可以用“==”判断两个数字是否相等。

    long double占用的内存是double的两倍,但表达数据的精度和double相同。

    在实际开发中,建议弃用float,只采用double就可以,long double暂时没有必要,但不知道以后的操作系统和编译器对long double是否有改进。

    四、浮点数的输出

    float采用%f占位符。

    double采用%lf占位符。测试结果证明,double不可以用%f输入,但可以用%f输出,但是不建议采用%f,因为不同的编译器可能会有差别。

    long double采用%Lf占位符,注意,L是大写。

    浮点数输出缺省显示小数点后六位。

    浮点数采用%lf输出,完整的输出格式是%m.nlf,指定输出数据整数部分和小数部分共占m位,其中有n位是小数。如果数值长度小于m,则左端补空格,若数值长度大于m,则按实际位数输出。

    double ff=70001.538;
    printf("ff=%lf=
    ",ff);       // 输出结果是ff=70001.538000=
    printf("ff=%.4lf=
    ",ff);     // 输出结果是ff=70001.5380=
    printf("ff=%11.4lf=
    ",ff);   // 输出结果是ff= 70001.5380=
    printf("ff=%8.4lf=
    ",ff);    // 输出结果是ff=70001.5380=
    

    五、常用的库函数

    在接下来的内容中,我只介绍double,不再介绍float和long double两种数据类型相关的知识。

    以下是常用的浮点数函数,必须掌握。

    double atof(const char *nptr);       // 把字符串nptr转换为double
    double fabs(double x);                // 求双精度实数x的绝对值
    double pow(double x, double y);      // 求 x 的 y 次幂(次方)
    double round(double x);               // double四舍五入
    double ceil(double x);                // double向上取整数
    double floor(double x);               // double向下取整数
    double fmod(double x,double y);      // 求x/y整除后的双精度余数
    // 把双精度val分解成整数部分和小数部分,整数部分存放在ip所指的变量中,返回小数部分。
    double modf(double val,double *ip);
    

    还有一些数据计算函数,如正弦、对数、指数等,实际开发中极少使用,大家要用的时候再查资料,我就不介绍了。

    六、整数转换为浮点数

    示例(book77.c)

    /*
     * 程序名:book77.c,此程序测试整数与浮点数的转换。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    
    int main()
    {
      int ii=3;
      int jj=4;
      double dd;
    
      dd=ii;        // 可以
      printf("dd is %.2lf
    ",dd);
    
      dd=ii/jj;     // 不行
      printf("dd is %.2lf
    ",dd);
    
      dd=(double)ii/jj;  // 可以
      printf("dd is %.2lf
    ",dd);
    }
    

    运行效果

    在这里插入图片描述

    需要特别注意的是dd=ii/jj这一行代码,dd的值0,不是0.75,有点意外,所以,如果对整数转换为浮点数没有把握,加(double)强制转换是个好办法。关于数据类型的转换,在《C语言数据类型转换》章节中将有更详细的介绍。

    七、应用经验

    浮点数有一些坑,例如两个浮点数不相等和精度的问题,在实际开发中,我们经常用整数代替浮点数,因为整数是精确的,效率也更高。

    例如人的身高一米七五,以米为单位,用浮点数表示是1.75米,如果以厘米为单位,用整数表示是175。

    long整数的取值是-9223372036854775808~9223372036854775807,有效数字是19位,而double的有效数字才15-16位,所以,整数可以表达的小数更大的数,更实用,麻烦也更少。

    货币:1.75元,如果采用0.01元为单位就是175,采用0.001元为单位就是1750,如果您说要更多小数怎么办?您这是钻牛角尖。

    码农之道:高水平的程序员不容易掉坑里,注意,是不容易,不是不会,最好的方法是不要靠近坑。

    八、科学计数法

    在实际开发中,我们很少使用科学计数法,但是它经常出现在计算机系统中,例如浮点数在内存中的存放方式就是科学计数法,所以我们还是有必要学习科学计数法。

    科学记数法是一种记数的方法。把一个数表示成a与10n相乘的形式(1≤|a|<10,n为整数),这种记数法叫做科学记数法。当我们要书写或运算某个较大或较小且位数较多时,用科学记数法免去浪费很多空间和时间。

    例如:51400000000=5.14×1011,计算机表达10的幂是一般是用E或e,也就是51400000000=5.14E11或5.14e11。

    用科学记数法表示数时,不改变数的符号,只是改变数的书写形式而已,可以方便的表示日常生活中遇到的一些极大或极小的数 。如:光的速度大约是300,000,000米/秒;全世界人口数大约是:6,100,000,000,这样的数书写和显示都很不方便,为了免去写这么多重复的0,将其表现为这样的形式:6,100,000,000=6.1×109,即6.1E9或6.1e9。

    0.00001=1×10-5,即绝对值小于1的数也可以用科学记数法表示为a乘10-n的形式。即1E-5或1e-5。

    科学计数法采用%e或%E输出,完整的输出格式是%m.ne或%m.nE,指定输出数据整数部分和小数部分共占m位,其中有n位是小数。如果数值长度小于m,则左端补空格,若数值长度大于m,则按实际位数输出。

    示例(book78.c)

    /*
     * 程序名:book78.c,此程序测试浮点数据的科学计数法。
     * 作者:C语言技术网(www.freecplus.net) 日期:20190525
    */
    #include <stdio.h>
    
    int main()
    {
      double dd;
    
      dd=123000000;
      printf("dd is  %.2e
    ",dd);
    
      dd=-123000000;
      printf("dd is %.2e
    ",dd);
    
      dd=0.0000000123;
      printf("dd is  %.2e
    ",dd);
    
      dd=-0.0000000123;
      printf("dd is %.2e
    ",dd);
    }
    

    运行效果

    在这里插入图片描述

    九、课后作业

    1)编写示例程序,类似本章节的book71.c、book73.c、book74.c、book75.c、book77.c、book78.c,编译并运行它,程序员是写出来的,不是看出来的,熟能生巧,您每天的付出都有意义。

    2)编写示例程序,测试浮点数赋值超过取值范围的后果。

    3)关于浮点数在内存中的存储方式,建议大家去百度一下(搜索关键字为C语言浮点数存储方式),了解一下相关的概念。

    4)编写示例程序,测试把浮点数赋给整数变量的结果,并思考原因。

    5)本题作业建议在学完《C语言数据类型转换》后再做,因为有知识点交叉,重写浮点数的常用库函数,实现其功能,函数的声明如下:

    double FABS(const double x);          // 求双精度实数x的绝对值
    double ROUND(const double x);         // double四舍五入
    double CEIL(const double x);          // double向上取整数
    double FLOOR(const double x);         // double向下取整数
    // 把双精度val分解成整数部分和小数部分,整数部分存放在ip所指的变量中,返回小数部分。
    double MODF(double val,double *ip);  
    

    十、版权声明

    C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
    来源:C语言技术网(www.freecplus.net)
    作者:码农有道

    如果文章有错别字,或者内容有错误,或其他的建议和意见,请您留言指正,非常感谢!!!

  • 相关阅读:
    Amazon Route 53
    监控应用程序负载均衡器ALB
    DynamoDB 流
    DynamoDB 中的限制
    Amazon SNS 消息属性
    关于基于 SAML 2.0 的联合身份验证
    Amazon EBS 性能提示
    Laravel5.1注册中间件的三种场景
    编译LNMP环境
    傻瓜式搭建LAMP环境
  • 原文地址:https://www.cnblogs.com/wucongzhou/p/12498838.html
Copyright © 2020-2023  润新知