C语言中int到float的强制类型转换

C语言|深入浅出讲解int转换为float全过程(附2017年统考大题案例) int转换为float类型为什么会发生精度损失? 精度损失的详细过程究竟是什么样的? 什么样情况float会发生精度损失?没有弄懂2017年浮点数统考大题? 这一篇用2017年统考大题案例帮你更深的理解浮点数的存储规则。 阅读详情
AI摘要

本文详细解析了C语言中32位int型数据强制转换为float型时精度损失的原因。通过深入探讨IEEE浮点数标准,解释了float型变量的内部表示方法及其与int型变量在位数上的差异。

最近在看一本名为的书。由于我所看过的计算机理论方面的书较少,加上自己大学期间一直也不用功,所以对于计算机的工作原理以及程序的工作方式我始终只知甚少,印象也十分模糊。

不过,应该说我碰到了一本好书。至少,通过昨晚对浮点数一章的阅读(呃...我的确之前对浮点数从没弄明白过),我终于了解了C语言中为什么32位int型数据强制转换到float型会出现精度不能完全保留的现象:

首先来看看我们可爱的int型变量吧,在一台典型的32位机器上一个有符号的int型的取值范围为-2147483648 ~ 2147483647(-2^31 ~ (2^31-1))(注1)。也就是说,在一个4字节(32位2进制),除去首位用于符号位表示正负外,其余的31位都是数字的有效位。

下面再来看看“万恶的”float型变量:根据IEEE的浮点标准,一个浮点数应该用下述形式来表示: 
V=(-1)^s * M * 2^E (公式1)
在C语言中,32位的float型变量有着这样的规定:首位表示符号位s,接下来的8位(指数域)用于表示2的指数E,剩余的23位(小数域)表示M(取值范围为[1,2)或[0,1))。除了上述规定以外,根据指数域的二进制表示情况不同,被编码的float型数字又可以分成三种情况——
1、规格化值。当指数域的8个二进制数字既非全零又非全1时,float数值就是这种情况。设指数域的八位二进制所表示的十进制数为e, 则公式1中的E就是 E = e - (2^7 - 1) (公式2);
而且此时,将小数域所表示的二进制假设为(f22)(f21)...(f1)(f0) (注2) ,则该小数域所表示的值即为f = 0.(f22)(f21)...(f1)(f0).于是M = 1 + f
2. 非规格化值。当指数域的8个二进制数字为全0时,float数值就为这种情况。这时指数域所表示的十进制数为0,规定指数值为 E = 1 - (2^7 - 1),也就是E为定值-126;此时小数域的值仍表示f = 0.(f22)(f21)...(f1)(f0),但是M的值却变成M = f。
3. 特殊值。当指数域的8个二进制数字为全1时即为这种情况。当小数域为全零时,该float值根据符号位的不同表示正无穷或者负无穷;当小数域为非全零时,该float值为NaN(Not a Number)。

以上,只是在C语言中对int和float的规约。具体在代码中执行强制类型转化究竟会发生什么?从下面两句很简单的语句开始:

 

int a = 3490593;
float b = (float)a;

 


那么在内存中a和b究竟存放的是什么值呢?

将a展开为二进制,其值为0000 0000 0011 0101 0100 0011 0010 0001,其十六进制即为0x00354321。 因为要转化为float型,所以首先要对上述二进制的表示形式改变为 M * 2^E 的形式.由于该数明显大于1,所以按照IEEE的标准,其浮点形势必然为规格化值。因此 ,转化后的形式为 
a = 1.101010100001100100001 * 2^21

根据 规格化值的定义,M = 1 + f. 所以f = 0.101010100001100100001.因为float型变量的小数域一共23位。所以b的最后23位可以得出,其值为10101010000110010000100

下面再演绎指数域的值:因为a的指数表示法中,指数E = 21。根据公式2,e = E + (2^7 -1) = 148.所以可以得出b的指数域的二进制表示为:10010100。在加上原数为正,所以符号位s=0。

所以,可以得出b的二进制表示为0 10010100 10101010000110010000100。转化为十六位进制则是0x4A550C84。换句话说,它存储在内存中的值是与a是完全不同的。但是其间还是有关联性的——a的首位为1的数值位后的二进制表示是与b的小数域完全相同的。

很快,问题就出现了。int型的有效位数是31,而float型小数域的有效位只有23位,也就是说如果上面的a的二进制的有效位超过了24位,那么float型的小数域的精度就不够了。因此必须进行舍入。比如:如果上面的a的二进制为0000 0001 1111 0101 0100 0011 0010 0001。这时b的小数域必须有24位才够,但是,这显然是不现实的,因此必须舍入到23位,舍入的原则是:所得结果的最低有效位为0。因此这个a在转换到float时,其精度就会丢失,因为该float的最后23位变成了11110101010000110010000——这显然是与原值不符的。

实际上,C语言中对于double型在32位机器上的小数域有52位,对于int型的31位有效位是绰绰有余了。这就是为什么大部分C语言教材上鼓励读者在执行强制类型转换时将int型转换成double。同时,这可能也是为什么int型能够直接隐式转换到double型的缘故。

注1:x ^ y表示 x的y次方
注2:(fn)取0或1

http://seapalace.blog.sohu.com/1586858.html

对文中关于e的描述不是很理解,如上文标红色部分。我按照上述描述可以做到整数2,3的手动转换到浮点数,就是不能对1做手动转换。后来又找到了维基上的描述:

http://zh.wikipedia.org/wiki/IEEE_754

贴出部分:

 

整体呈现[编辑]

IEEE 754浮点数的三个域

二进制浮点数是以符号数值表示法的格式存储——最高有效位被指定为符号位(sign bit);“指数部份”,即次高有效的e个比特,存储指数部分;最后剩下的f个低有效位的比特,存储“尾数”(significand)的小数部份(在非规约形式下整数部份默认为0,其他情况下一律默认为1)。

指数偏移值[编辑]

指数偏移值(exponent bias),是指浮点数表示法中的指数域的编码值为指数的实际值加上某个固定的值,IEEE 754标准规定该固定值为2e-1 - 1[2],其中的e为存储指数的比特的长度。

以单精度浮点数为例,它的指数域是8个比特,固定偏移值是28-1 - 1 = 128−1 = 127.单精度浮点数的指数部分实际取值是从128到-127。例如指数实际值为1710,在单精度浮点数中的指数域编码值为14410,即14410 = 1710 + 12710.

采用指数的实际值加上固定的偏移值的办法表示浮点数的指数,好处是可以用长度为e个比特的无符号整数来表示所有的指数取值,这使得两个浮点数的指数大小的比较更为容易。

规约形式的浮点数[编辑]

如果浮点数中指数部分的编码值在0 < exponent < 2e-1之间,且尾数部分最高有效位(即整数字)是1,那么这个浮点数将被称为规约形式的浮点数。

非规约形式的浮点数[编辑]

如果浮点数的指数部分的编码值是0,尾数为非零,那么这个浮点数将被称为非规约形式的浮点数。IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值大1.例如,最小的规约形式的单精度浮点数的指数部分编码值为1,指数的实际值为-126;而非规约的单精度浮点数的指数域编码值为0,对应的指数实际值也是-126而不是-127。实际上非规约形式的浮点数仍然是有效可以使用的,只是它们的绝对值已经小于所有的规约浮点数的绝对值;即所有的非规约浮点数比规约浮点数更接近0。规约浮点数的尾数大于等于1且小于2,而非规约浮点数的尾数小于1且大于0.

IEEE 754-1985标准采用非规约浮点数,源于70年代末IEEE浮点数标准化专业技术委员会酝酿浮点数二进制标准时,Intel公司对渐进式下溢出(gradual underflow)的力荐。当时十分流行的DEC VAX机的浮点数表示采用了突然式下溢出(abrupt underflow)。如果没有渐进式下溢出,那么0与绝对值最小的浮点数之间的距离(gap)将大于相邻的小浮点数之间的距离。例如单精度浮点数的绝对值最小的规约浮点数是1.0\times 2^{-126},它与绝对值次小的规约浮点数之间的距离为2^{-126}\times 2^{-23}=2^{-149}。如果不采用渐进式下溢出,那么绝对值最小的规约浮点数与0的距离是相邻的小浮点数之间距离的2^{23}倍!可以说是非常突然的下溢出到0。这种情况的一种糟糕后果是:两个不等的小浮点数X与Y相减,结果将是0.训练有素的数值分析人员可能会适应这种限制情况,但对于普通的程序员就很容易陷入错误了。采用了渐进式下溢出后将不会出现这种情况。例如对于单精度浮点数,指数部分实际最小值是(-126),对应的尾数部分从1.1111\ldots 11, 1.1111\ldots 10一直到0.0000\ldots 02, 0.0000\ldots 01,相邻两小浮点数之间的距离(gap)都是2^{-126}\times 2^{-23}=2^{-149};而与0最近的浮点数(即最小的非规约数)也是2^{-126}\times 2^{-23}=2^{-149}。

特殊值[编辑]

这里有三个特殊值需要指出:

  1. 如果指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
  2. 如果指数 = 2^{e} - 1并且尾数的小数部分是0,这个数是±∞(同样和符号位相关)
  3. 如果指数 = 2^{e} - 1并且尾数的小数部分非0,这个数表示为不是一个数(NaN)。

以上规则,总结如下:

形式指数小数部分
零00
非规约形式0非0
规约形式1到2^e-2任意
无穷2^e-10
NaN2^e-1非零

32位单精度[编辑]

单精度二进制小数,使用32个比特存储。

1823 位长
SExpFraction
3130至23
偏正值(实际的指数大小+127)
22至0 位编号(从右边开始为0)

S为符号位,Exp为指数字,Fraction为有效数字。 指数部分即使用所谓的偏正值形式表示,偏正值为实际的指数大小与一个固定值(32位的情况是127)的和。采用这种方式表示的目的是简化比较。因为,指数的值可能为正也可能为负,如果采用补码表示的话,全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较。正因为如此,指数部分通常采用一个无符号的正数值存储。单精度的指数部分是−126~+127加上偏移值127,指数值的大小从1~254(0和255是特殊值)。浮点小数计算时,指数值减去偏正值将是实际的指数大小。

单精度浮点数各种极值情况:

类别正负号实际指数有偏移指数指数域尾数域数值
零0-12700000 0000000 0000 0000 0000 0000 00000.0
负零1-12700000 0000000 0000 0000 0000 0000 0000−0.0
1001270111 1111000 0000 0000 0000 0000 00001.0
-1101270111 1111000 0000 0000 0000 0000 0000−1.0
最小的非规约数*-12600000 0000000 0000 0000 0000 0000 0001±2−23 × 2−126 = ±2−149 ≈ ±1.4×10-45
中间大小的非规约数*-12600000 0000100 0000 0000 0000 0000 0000±2−1 × 2−126 = ±2−127 ≈ ±5.88×10-39
最大的非规约数*-12600000 0000111 1111 1111 1111 1111 1111±(1−2−23) × 2−126 ≈ ±1.18×10-38
最小的规约数*-12610000 0001000 0000 0000 0000 0000 0000±2−126 ≈ ±1.18×10-38
最大的规约数*1272541111 1110111 1111 1111 1111 1111 1111±(2−2−23) × 2127 ≈ ±3.4×1038
正无穷01282551111 1111000 0000 0000 0000 0000 0000+∞
负无穷11282551111 1111000 0000 0000 0000 0000 0000−∞
NaN*1282551111 1111non zeroNaN
* 符号位可以为0或1 .

64位双精度[编辑]


相关文章连接:

《C++类型转换方式总结 》http://www.cnblogs.com/ider/archive/2011/08/05/cpp_cast_operator_part6.html

《C++标准转换运算符dynamic_cast》http://www.cnblogs.com/ider/archive/2011/08/01/2123298.html

《C++标准转换运算符static_cast 》http://www.cnblogs.com/ider/archive/2011/07/31/2122385.html

《C++标准转换运算符reinterpret_cast》http://www.cnblogs.com/ider/archive/2011/07/30/2121953.html

C语言基础知识(二) 第二部分:类型转换 1、隐式类型转换(自动转换) 在有多种数据类型混合计算的时候,若未人为控制类型,系统会自动进行类型转换 转换的规则是:存储长度较短的转换成存储长度较长的,且不丢失数据 char--->short--->int--->unsigned int(--->long--->unsigned long)--->double float--------↑ 2、赋值转换 阅读详情

相关推荐

C++强制类型转换

如果读者,看过小林之前推送C语言的文章,会发现C++的强制类型转换和C语言一样,因为C++编写者将C语言的优点保留了下来,除此之外C++还特别增加了。在C++的表达式中,不同的数据类型会自动地转换类型进行运算,但有的时候也需要程序员自己进行强制类型转换,将某个表达式转换成自己所需要的数据类型。如果进行强制类型转换的对象是一个变量,则该变量的括号可以省略;在强制类型转换时,会得到一个中间变量,原来变量的类型未发生变化,但是如果从高精度向低精度转换时,会丢失精度。强制类型转换的一般形式为(类型名) (表达式).

weixin_54707168的博客 1663

C语言基础知识 - 笔记(一)

C语言基础知识 - 笔记(一) 数据类型 char—8位—127—255 int—16位—32767—65535 short—16位—32767—65535 long—32位—2147483647—4294967295 在表达式中,P是指针,*P是指向它的内容 函数指针 V.S. 指针函数 函数指针 int (*fun) ():本质上是一个指针,指向一个函数的地址,用于函数调用 指针函数

wangyu2010302660001的专栏 2277

C 语言类型转换

类型转换允许我们将一种数据类型转换为另一种数据类型。在C语言中,我们使用强制转换运算符进行类型转换,用(type)表示。注意:始终建议将较低的值转换为较高的值,以避免数据丢失。

Tom_Jerry__的博客 208

怎样在C语言中进行强制类型转换

1.强制类型转换的示例 (float) a; //将变量 a 转换为 float 类型 (int)(x+y); //把表达式 x+y 的结果转换为 int 整型 (float) 100; //将数值 100(默认为int类型)转换为 float 类型 2.代码举例 #include <stdio.h> int main() { float m=6.4; int n; n = (int)m; printf("%d",n); return 0; } //这里输出结果.

优快云_Marker的博客 9275

TexGen模型导出到ABAQUS的inp文件:如何快速修改纱线材料属性(避坑指南)

本文针对TexGen模型导出到ABAQUS的inp文件后纱线材料属性缺失或错误的问题,提供了高效的解决方案。文章详细解析了inp文件结构,指导用户如何手动定位并修改纱线材料属性,并提供了可批量处理的Python脚本,帮助用户快速、精准地完成材料参数赋值,有效提升复合材料仿真工作效率。

ice55的博客 602

华为Watch的ECG功能技术分析

华为Watch的ECG(心电图)功能通过硬件传感器、算法优化和医疗认证的结合,实现了对心脏电活动的监测和房颤(AFib)等心律失常的预警。采用医疗级ECG模拟前端芯片(AFE),如TI(德州仪器)的ADS1292R等,支持低噪声、高采样率(通常≥200Hz)。结合PPG(光学心率)数据交叉验证,提高检测可靠性(如ECG和PPG心率不一致时触发警告)。通过RR间期变异性判断心律是否规则,识别房颤(AFib)的典型特征(如不规则不规则心律)。结合加速度计数据,识别手臂运动导致的信号失真,动态调整算法参数。

xu_wenming的博客 6442

c语言float转换为int_2.2 C++强制类型转换

点击上方“C语言入门到精通”,选择置顶第一时间关注程序猿身边的故事作者闫小林白天搬砖,晚上做梦。我有故事,你有酒么?强制类型转换运算符在C++的表达式中,不同的数据类型会自动地转换类型进行运算,但有的时候也需要程序员自己进行强制类型转换,将某个表达式转换成自己所需要的数据类型。强制类型转换的一般形式为(类型名) (表达式)如果进行强制类型转换的对象是一个变量,则该变量的括号可以省略;如果...

weixin_39900830的博客 1243

泛微E10 eBuilder低代码平台避坑指南:新手最容易犯的5个错误及解决方案

本文针对泛微E10 eBuilder低代码平台的新手开发者,总结了5个最常见错误及解决方案,包括表单联动配置、流程设计权限、动作流时序、数据加工类型转换和权限管理过度配置等问题。通过实战经验和代码示例,帮助开发者避开常见陷阱,提升开发效率。

weixin_30919429的博客 540

C语言中int到float的强制类型转换(转)

在看csapp书时对于书上的一个32位机器上强制转换的例题苦思冥想不得解:x==(int)(float)x为什么是错的?x转换为float不应该是舔几个0么,再转换为Int又将小数点后的0去了么。知道看了这篇博文才知道一切都得从二进制的角度来看。 转:http://seapalace.blog.sohu.com/1586858.html 最近在看一本名为的书。由于我所看过的计算机理

格林先生的专栏 8816

YOLOv8中间特征层可视化

在通过观察这些特征,可以清楚地看到模型如何逐步将输入图像转化为有意义的表示。

weixin_45314480的博客 6890

博通PEX89000 PCIe 5.0交换芯片:如何为AI集群构建高效GPU互联架构

本文深入解析了博通PEX89000 PCIe 5.0交换芯片如何为AI集群构建高效的GPU互联架构。该芯片通过提供高带宽、低延迟的PCIe 5.0交换能力,打破传统GPU通信的带宽瓶颈,并支持多主机共享、资源池化及软件定义拓扑,从而显著提升大规模AI训练与推理任务的效率与资源利用率。

weixin_29214559的博客 411

C语言强制类型转换

强制类型转换是通过类型转换运算来实现的。其一般形式为: (类型说明符) (表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。例如: (float) a 把a转换为实型(int)(x+y) 把x+y的结果转换为整型在使用强制转换时应注意以下问题:1.类型说明符和表达式都必须加括号(单个变量...

hxh的博客 1万+

多智能体系统在AI物流优化中的实际应用案例

订单波峰波谷难应对(如双11订单量暴增300%);动态干扰难处理(如突发交通拥堵、客户临时改地址);全局优化难实现(单辆车最优≠整体最优)。本文聚焦“多智能体系统(MAS)”这一AI技术,讲解其如何通过“群体智能”破解物流调度难题,并结合实际案例展示落地效果。本文从“生活故事→核心概念→技术原理→实战案例→未来趋势”逐步展开,用“快递员团队协作送外卖”类比MAS运作,结合Python代码模拟任务分配,最后通过某物流企业的真实项目验证效果。

AIGC应用创新大全的博客 1631

从double到float的强制类型转换

#include &amp;amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;amp;gt; union FLOATUN{ unsigned int a; float b; }; int main(){ FLOATUN fun; fun.b = 12.34; printf(&amp;amp;amp;amp;quot;c:%x\n&amp;amp;amp;amp;quot;,fun.a); doubl

qianshishangdi的博客 3万+

C++怎么学?零基础也可以,一份完整学习路线图助你搞定!

提供一条清晰、系统且实践导向的C++学习路径。从基础语法、面向对象、泛型编程、异常处理,逐步深入STL、智能指针、并发编程等现代C++高级特性。无论是新手还是希望提升,通过系统学习与项目实践,助您将理论知识转化为实际解决问题的能力。

Lion_Long的博客 4022

项目篇:移动平台机械臂视觉定位抓取实施(基于ROS架构)

ROS包内容: 这篇日志的目的是快速项目实施,所以详细的部分会不断补充。 1、相机采集包(创建抓取图像服务,单张) Realsense Camera(微软深度摄像头,官方提供ros包) Pylon Camera(basler相机,官方提供ros包) 2、定位算法包(抓取图像,定位标志物) Aruco_ros (二维码定位,官方提供ros包) Apriltag (二维码定位,官方提供ros包)...

南北粉面馆 6049

C语言指针强制类型转换

原文链接 概要: C语言中,任何一个变量都必须占有一个地址,而这个地址空间内的0-1代码就是这个变量的值。不同的数据类型占有的空间大小不一,但是他们都必须有个地址,而这个地址就是硬件访问的依据,而名字只是提供给程序员的一种记住这个地址的方便一点的方法。但是,不同的变量在机器中都是0-1代码,所以,我们不能简单的通过检查一个值的位来判断它的类型。 例如,定义如下: int a; float b; double c; long double d; (假设它们所占的字节分别是4、8、8、10,..

Find的博客 4821

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

C语言中的数据转换(自动类型转换与强制类型转换)

摘要:C语言数据类型转换分为自动(隐式)和强制(显式)两种。自动转换由编译器按优先级规则(如char→int→float→double)处理运算时的类型提升;强制转换通过(type)表达式实现,可能引发精度丢失或溢出。重点包括:1)int与short转换涉及截断或符号扩展;2)有符号/无符号整型转换需注意数值解析差异;3)float与int转换会丢失小数或精度。转换时需考虑取值范围,避免数据异常。

RZM666的博客 1167

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

c语言中的类型强制转换

强制类型转换是通过类型转换运算来实现的。其一般形式为: (类型说明符) (表达式) 其功能是把表达式的运算结果强制转换成类型说明符所表示的类型。例如: (float) a 把a转换为实型(int)(x+y) 把x+y的结果转换为整型在使用强制转换时应注意以下问题:1.类型说明符和表达式都必须加...

chuanzou4767的博客 312

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

C语言·强制类型转换运算符

一般形式: (类型名)(表达式\常量\变量) (double)a 不管a原来是什么类型,此时临时将其强制变成double类型。 例: (int)(x+y)将x+y的值转换为整型 (float)(5%3)将5%3的值转换成单精度型2.0 注意: 1、优先级2级 2、(int)(x+y)与(int)x+y 【转换x加y的意思】意义不同 3、类型转换得一个中间值,原变量类型没有发生变化。 笔记于慕课...

3Y的太空充电站 8552

C语言基础——强制类型转换

强制类型装换: (数据类型)+变量 这里我用了time.h用于获取程序使用的时间 以下是代码: #include<stdio.h> #include<stdlib.h> #include<time.h> //强制类型装换: //(数据类型)+变量 //数据类型:int,float,char,double,unsigned,short,long //float->int int change1() { float num; printf("请输入一个浮点数(小

qq_51553982的博客 1252

C/C++中的类型转换

C/C++中的类型转换

2402_86735906的博客 273

C语言不同数据类型间的混合运算转换规则+常见数据类型

在程序中经常会遇到不同类型的数据进行运算,若一个运算符两侧的数据类型不同,则先自动进行类型转换,使两者具有同一类型,然后进行运算,现将规律总结如下: 1. +. -. *. /运算的两个数中有一个数为float或double型,结果是double型,因为系统将所有float型数据都先转换为double型,然后进行运算; 2. 若int型与float或double型数据进行运算,先将int型和f...

小武的博客 9856
上一篇: C++、C中有关double、float类型转换成int型,及取整,丢失精度问题。
下一篇: VC多线程编程
死神在世
博客等级 码龄14年 233粉丝 102原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值