(通俗解释)浮点数的存储与精度丢失问题

(通俗解释)浮点数的存储与精度丢失问题

浮点数的存储

浮点型变量在计算机内存中占用4个字节(4 Byte),即32-bit,一个浮点数由3部分组成:符号位、指数 和 底数(尾数);

可以理解为浮点数是用科学计数法来存储数据,如

1.51

×

1

0

5

-1.51 \times 10^{-5}

−1.51×10−5

符号位:0=正数;1=负数;占用最高位1bit

指数部分:表示10的X次幂,即例子中的-5。占用 8bit (11bit) 空间来表示,8bit 表示数值范围:0-254 ( 0 和 255 被保留用于表示特殊值);为了能表示负数,正负各一半,采用移位存储方式,实际值需要减去127,所以指数可从 -126到+127.。

特例:浮点数 为0时,指数和底数都为0,但此前的公式不成立。因为2的0次方为1,所以,0是个特例。这个特例也不用认为去干扰,编译器会自动去识别。

底数部分:表示此浮点数的实际值,使用2进制数来表示;占用23bit,因为二进制第一位一定是1,所以可以省略,所以实际可以表示24bit的数。

二进制转十进制浮点数:

看下-12.5在计算机中存储的具体数据:0xC1 0x48 0x00 0x00

二进制:1100 0001 0100 1000 0000 0000 0000 0000

格式: SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM

S: 为1,是个负数。

E:(8-bit)为 10000010 转为10进制为130,130-127=3,即实际指数部分为3.

M:(23-bit)为 10010000000000000000000。需要加上被省略的第一位1底数实际上是:1.10010000000000000000000(二进制)

实际值

=

S

×

M

×

1

0

E

实际值 = S \times M \times 10^E

实际值=S×M×10E

通过指数部分E的值来调整底数部分M的值

调整方法为:如果指数E为负数,底数的小数点向左移,如果指数E为正数,底数的小数点向右移。小数点移动的位数由指数E的绝对值决定。这里,E为正3,使用向右移3为即得: 1100.10000000000000000000 二进制转十进制

小数点左边的1100 表示为$ (1 × 2^3) + (1 × 2^2) + (0 × 2^1) + (0 × 2^0)$, 其结果为12 。小数点右边的 .100… 表示为 $(1 × 2^{-1}) + (0 × 2^{-2}) + (0 × 2^{-3}) + … $,其结果为.5 。以上二值的和为12.5 符号位计算

由于S 为1,使用为负数,即-12.5

十进制浮点数转为二进制:

下面看下如何将一浮点数装换成计算机存储格式中的二进制数。 举例将19.625换算成 float型。

转为二进制

整数部分采用 “除2取余,逆序排列” 10011

19 / 2 = 9...1

9 / 2 = 4...1

4 / 2 = 2...0

2 / 2 = 1...0

1 / 2 = 0...1

小数部分采用 “乘2取整,顺序排列” 101

0.625 * 2 = 1.250 取1

0.250 * 2 = 0.500 取0

0.500 * 2 = 1.0 取1

合并得到 10011.101

底数部分移位,使底数变成1.xxxx

小数点左移4位,变成1.0001101这样底数为:1.0001101指数为:4+127=131,二进制为:1000011 符号位为0,因为是正数;

合并

初步合并得到0 1000011 0001101后面补0,补成32-bit,得到 0100 0011 0001 1010 0000 0000 0000 0000

精度丢失

精度丢失是计算机中浮点数无法精确表示某些十进制数时导致的误差现象

主要原因是 小数部分的计算方式(乘2取整)存在循环的问题,而浮点数的底数部分位数有限,因此无限循环的二进制小数会被截断,存储为近似值。

例如:十进制0.1 → 二进制0.0001100110011...(无限循环截取23位或52位)

0.1 * 2 = 0.2 取0

0.2 * 2 = 0.4 取0

0.4 * 2 = 0.8 取0

0.8 * 2 = 1.6 取1

0.6 * 2 = 1.2 取1

0.2 * 2 = 0.4 取0

...无限循环

double sum = 0;

for (int i = 0; i < 10; i++) sum += 0.1; // 结果可能为0.9999999999999999而非1.0

解决方案

定点数替代:对货币等场景,使用整数表示最小单位(如分)避免浮点运算。高精度类型:使用BigDecimal(Java)、decimal(C#/Python)等十进制类型。误差容忍比较:比较浮点数时允许微小误差(如 Math.abs(a - b) < 1e-10)。

参考文献

推荐阅读 - c语言中float、double、long double在内存中存储方式

相关推荐

被《黑神话:悟空》带火的那些游戏取景地
beat365手机版官方网站

被《黑神话:悟空》带火的那些游戏取景地

🗓️ 07-09 👁️ 564
文明6全文明强度权威排行:巴比伦登顶
beat365手机版官方网站

文明6全文明强度权威排行:巴比伦登顶

🗓️ 08-31 👁️ 2057
华夏幸福
beat365手机版官方网站

华夏幸福

🗓️ 07-15 👁️ 1700
意大利世界杯能晋级吗?深度分析蓝衣军团的晋级之路
365bet正网注册

意大利世界杯能晋级吗?深度分析蓝衣军团的晋级之路

🗓️ 08-23 👁️ 9242
Word文档被锁定无法编辑?这几种解决方法请收好!
beat365手机版官方网站

Word文档被锁定无法编辑?这几种解决方法请收好!

🗓️ 07-29 👁️ 143
砭石手串怎么盘?这些细节一定要清楚!
365bet正网注册

砭石手串怎么盘?这些细节一定要清楚!

🗓️ 08-12 👁️ 3333
国粹中国书体《燕体》
beat365手机版官方网站

国粹中国书体《燕体》

🗓️ 09-21 👁️ 6818
作为二战的战败国,为何日本能建造7艘准航母?
英国beat365官方登录

作为二战的战败国,为何日本能建造7艘准航母?

🗓️ 08-28 👁️ 7336
世界杯首场比赛为何选择俄罗斯对阵沙特背后的战略考量与意义
beat365手机版官方网站

世界杯首场比赛为何选择俄罗斯对阵沙特背后的战略考量与意义

🗓️ 09-25 👁️ 9446
如何找到自己的天赋?通常情况下,我们把天赋分为8种,分别是:语言天赋、音乐天赋、逻辑思维天赋、视觉天赋、人际关系天赋、自...
描写鱼的词语
英国beat365官方登录

描写鱼的词语

🗓️ 06-30 👁️ 7825
当年风靡一时的动漫《死神》,是怎样走向停播的呢?
365bet正网注册

当年风靡一时的动漫《死神》,是怎样走向停播的呢?

🗓️ 09-22 👁️ 8063