小白入门C语言之浮点数详解

本文详细介绍了C语言中的浮点数类型,包括float、double和long double,以及它们的内存占用和精度差异。强调了在实际编程中通常使用double代替float的原因。此外,还讲解了浮点数的输出格式和相关库函数,如atof、fabs、pow等,并展示了整数与浮点数之间的转换。最后,讨论了科学计数法在浮点数表示中的应用及其输出格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、浮点数概念

  • 浮点数也称小数或实数。
  • C语言中采用floatdouble关键字来定义小数,float称为单精度浮点型,double称为双精度浮点型,long double更长的双精度浮点型。
  • 在任何区间内(如1.0 到 2.0 之间)都存在无穷多个实数,计算机的浮点数不能表示区间内所有的值。
  • 占用内存的情况:
#include <stdio.h>
 
int main()
{
  printf("sizeof float is %d\n",sizeof(float));//sizeof float is 4
  printf("sizeof double is %d\n",sizeof(double));//sizeof float is 8
  printf("sizeof long double is %d\n",sizeof(long double));//sizeof float is 16
}
  • 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=\n",ff);       // 输出结果是ff=70001.538000=
printf("ff=%.4lf=\n",ff);     // 输出结果是ff=70001.5380=
printf("ff=%11.4lf=\n",ff);   // 输出结果是ff= 70001.5380=
printf("ff=%8.4lf=\n",ff);    // 输出结果是ff=70001.5380=

三、常用的库函数

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);

四、整数与浮点数的转换

  • 在浮点数的取值范围内,整数转换为浮点数不会有精度的损失,浮点数转换为整数后,会丢弃小数位。
#include <stdio.h>
 
int main()
{
  int ii=3;
  int jj=4;
  double dd;
 
  dd=ii;        // 可以
  printf("dd is %.2lf\n",dd); //dd is 3.00
 
  dd=ii/jj;     // 不行
  printf("dd is %.2lf\n",dd); //dd is 0.00
 
  dd=(double)ii/jj;  // 可以
  printf("dd is %.2lf\n",dd); //dd is 0.75
}

五、科学计数法

  • 用科学记数法表示数时,不改变数的符号,只是改变数的书写形式而已,可以方便的表示日常生活中遇到的一些极大或极小的数 。如:光的速度大约是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,则按实际位数输出。
#include <stdio.h>
 
int main()
{
  double dd;
 
  dd=123000000;
  printf("dd is  %.2e\n",dd);
 
  dd=-123000000;
  printf("dd is %.2e\n",dd);
 
  dd=0.0000000123;
  printf("dd is  %.2e\n",dd);
 
  dd=-0.0000000123;
  printf("dd is %.2e\n",dd);
}
  • 运行结果:
    在这里插入图片描述
<think>嗯,用户想了解C语言浮点数精度损失的原因及解决方法,特别是关于IEEE 754的内容。首先,我需要回忆一下浮点数的基本表示方法。根据IEEE 754标准,浮点数由符号位、指数部分尾数部分组成。比如单精度浮点数用32位,双精度用64位。精度损失的主要原因可能是因为二进制无法准确表示某些十进制小数,比如0.1这样的数在二进制中是无限循环的,存储时会被截断,导致精度丢失。另外,当进行大数小数相加时,由于指数对齐,小数部分可能会被舍去,这也是精度问题的一个原因。 用户提到的解决方案可能包括使用更高精度的数据类型,比如用double代替float,或者使用整数运算来避免浮点误差。还有可能需要用到特定的库,比如GNU的多精度算术库。此外,比较浮点数时应该用范围比较而不是直接相等判断,这也是常见的建议。 需要确认引用的资料是否正确。根据用户提供的引用,引用1引用2解释了IEEE 754标准以及二进制表示导致的精度问题,引用34提到了C语言中的具体处理方法解决方案。所以应该结合这些引用中的信息来组织答案。 可能用户在实际编程中遇到了浮点数计算不准确的问题,比如累加很多小数时结果出现偏差,或者在比较两个浮点数时出现意外结果。这时候需要解释清楚原因,并提供具体的解决办法,比如调整算法或使用特定的方法。 还需要注意回答的结构,按照用户的要求分原因解决方案两部分,每部分用子标题,并且正确使用LaTeX格式。比如提到IEEE 754的格式时,可以用$$...$$展示单精度双精度的结构。同时,代码示例要符合用户提供的引用中的例子,比如引用3中的C代码,可能需要解释其原理。 最后,生成的相关问题要围绕浮点数精度损失,可能涉及其他语言如Java、JS的情况,或者如何避免常见错误,以及不同应用场景中的处理方法。需要确保问题有针对性,帮助用户进一步学习。</think>### C语言浮点数精度损失原因及解决方案 --- #### 一、精度损失原因 1. **二进制无法精确表示某些十进制小数** 例如,十进制数 $0.1$ 在二进制中是无限循环小数 $0.0001100110011\dots$,存储时会被截断,导致精度丢失[^2]。 2. **IEEE 754 的位数限制** - **单精度(32位)**:符号位1位,指数8位,尾数23位 - **双精度(64位)**:符号位1位,指数11位,尾数52位 尾数位数有限,无法容纳无限精度的数值。例如,单精度浮点数最多只能保留约6-7位有效十进制数字[^1][^4]。 3. **运算中的精度损失** - **大数吃小数**:当两个相差极大的数相加时,小数可能因指数对齐被舍去。 - **累积误差**:多次运算后误差逐渐累积,例如循环累加 $0.1$ 时[^3]。 --- #### 二、解决方案 1. **选择更高精度类型** 使用 `double`(双精度)替代 `float`(单精度),以扩大尾数位数: ```c double a = 0.1; // 精度误差更小 ``` 2. **避免直接比较浮点数** 使用误差范围(epsilon)代替 `==` 判断: ```c #include <math.h> if (fabs(a - b) < 1e-6) { /* 视为相等 */ } ``` 3. **整数替代法** 将小数转换整数运算,例如货币计算中以分为单位: ```c int cents = 123; // 代表1.23元 ``` 4. **使用高精度库** 如 GNU MPFR 或 `decimal.h`(C99扩展): ```c #include <decimal/decimal.h> _Decimal32 a = 0.1DF; // 精确十进制浮点类型 ``` 5. **注意运算顺序** 先处理小数量级数值,减少大数吃小数的影响: ```c // 错误示例:sum += 1e10 + 0.1 → 0.1被舍去 // 正确示例:先累加小数再合并大数 ``` --- #### 三、IEEE 754 的底层处理(引用代码解析) 引用代码[^3]通过直接操作二进制位实现浮点数乘法近似: ```c float a = 12.3f, b = 4.56f; int c = *(int*)&a + *(int*)&b - 0x3f800000; // 通过调整指数近似计算乘积 printf("近似结果:%f\n", *(float*)&c); ``` 此方法依赖 IEEE 754 的二进制格式,但会引入额外误差,仅适用于特定场景。 ---
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值