C语言浮点数

小数在C语言中称为浮点数(floating-point number),有float、double和long double三种类型。相比于整数,浮点数能表示更广范围的、更精确的数,常用于数学和金融领域。

浮点数的数值表示:1.2311.5E16

C语言的浮点数遵循IEEE 754标准,其规格化的表示为:

( − 1 ) s i g n × 1. m a n t i s s a × 2 e x p o n e n t − o f f s e t = ( − 1 ) s i g n × ( 1 + m a n t i s s a 2 23 ) × 2 e x p o n e n t − 127 \mathbf{(-1)^{sign} \times 1.mantissa \times 2^{exponent - offset} = (-1)^{sign} \times (1+\frac{mantissa}{2^{23}}) \times 2^{exponent - 127}} (1)sign×1.mantissa×2exponentoffset=(1)sign×(1+223mantissa)×2exponent127

m a n t i s s a 2 23 \mathbf{\frac{mantissa}{2^{23}}} 223mantissa表示将mantissa的小数点移动至最前方。

C语言中的float可以叫做单精度浮点数,存储长度为4 byte。

系统通常使用32位bit存储单精度浮点数,其中,1位表示符号位sign,8位表示指数或阶码exponent的值及其符号,23位表示尾数mantissa或称为有效数字significand。符号位控制正负;指数控制了小数点的最后位置,决定了表示范围;尾数控制有效数字,也就是表示精度。指数使用移码1表示,偏置量为127;尾数使用原码表示,隐藏了1位整数部分1

小数的有效数字是指从左边第一个非零数字开始,一直到最后一个数字。例如,0.01230的有效数字位数为4,1.02的有效数字位数为3。

C标准规定float类型必须至少能表示6位有效数字,并且至少提供 1 0 − 37 ∼ 1 0 37 10^{-37} \sim 10^{37} 10371037​这个范围的数。

那float类型的实际精度是多少?

大部分的验证法如下:

由于 l o g 10 2 23 ≈ 6.92 log_{10}{2^{23}} \approx 6.92 log102236.92,得出精度为6-7位。

较少的验证法:

我们说的有效数字是在十进制情况下。假设mantissa达到最小,即最后一位为1,值为 2 − 23 ≈ 0.000000119 2^{-23} \approx 0.000000119 2230.000000119,第二小的为 2 − 22 ≈ 0.000000238 2^{-22} \approx 0.000000238 2220.000000238,其次为 2 − 21 ≈ 0.000000476 2^{-21} \approx 0.000000476 2210.000000476​,加上隐藏位1,这三个数之间的数是float类型无法进行表示的,也就是说,到了精度为8的时候,是无法表示所有数在内的,这只是部分精确。得出精度为7位。

本文考虑在计算有效位数的时候,加上对阶码的分析:

假设小数部分为 1. x x ⋅ ⋅ ⋅ x 1.xx···x 1.xx⋅⋅⋅x,计算阶码部分对它的影响后,变为 0.00 ⋅ ⋅ ⋅ 1 x x ⋅ ⋅ ⋅ x 0.00···1xx···x 0.00⋅⋅⋅1xx⋅⋅⋅x,最小正数为 2 − ( 126 − 23 ) = 0.00 ⋅ ⋅ ⋅ 100 ⋅ ⋅ ⋅ 0 ≈ 9.8607613 e − 32 2^{-(126-23)} = 0.00···100···0 \approx 9.8607613e-32 2(12623)=0.00⋅⋅⋅100⋅⋅⋅09.8607613e32,其次为 2 − 103 + 2 − 126 ≈ 9.8607624 e − 32 2^{-103}+2^{-126} \approx 9.8607624e-32 2103+21269.8607624e32​​。浮点数越小,变化幅度越小,密度越大。这样看能达到的最少有效位数是6。

然后是float类型的实际范围。当尾数和指数达到最大值时,达到float范围边界。由于指数为-127、128时有特殊用途2,所以指数最大为127,对应移码为1111 1101;尾数全1时最大。故 ± 1.111 ⋅ ⋅ ⋅ 1 × 2 127 ≈ ± 3.4 E 38 \pm 1.111···1 \times 2^{127} \approx \pm 3.4 E 38 ±1.111⋅⋅⋅1×2127±3.4E38​为float范围边界。

C语言的double类型是双精度浮点型,要求的最小范围与float相同,但标准扩展了最小有效数字位数到了10位。并且,增加了32位额外bit,既可以补充指数,也可以补充尾数,或者两者皆有之。无论哪种做法,至少产生13位有效数字。根据IEEE 754标准,双精度浮点型使用64位来存储,其中有1位用于符号位,11位用于指数部分,剩下的52位用于尾数部分。double的实际精度为16,验证方式同上。double的表示范围为 − 1.79 E308 ∼ + 1.79 E308 -1.79\text{E308} \sim +1.79\text{E308} 1.79E308+1.79E308

疑问:为什么无论哪种做法,至少产生13位有效数字?

一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快。

为了更高精度,C标准还提供了long double类型。其具体实现取决于系统,但是至少会比double更加精确。


  1. 移码又叫增码或偏置码,符号位使用1表示正数,使用0表示负数,数值部分与补码相同。 ↩︎

  2. 128对应的阶码 = 1000 0000 + 0111 1111 = 11111111 1111 1111 11111111​,-127的对应的阶码 = -0111 1111 + 0111 1111 = 0000 0000。 ↩︎

  • 17
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值