Lua和C++中的浮点数的比较
Posted ithiker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lua和C++中的浮点数的比较相关的知识,希望对你有一定的参考价值。
文章目录
问题
最近碰到Lua语言中的浮点数比较问题,如下:
print(9007199254740991 + 0.0 == 9007199254740991)
print(9007199254740992 + 0.0 == 9007199254740992)
print(9007199254740993 + 0.0 == 9007199254740993)
上面的代码输出为:
true
true
false
将下面类似的代码改写为C/C++中的代码:
#include <iostream>
#include <iomanip>
int main()
std::cout << std::boolalpha;
std::cout<< (9007199254740991 + 0.0 == 9007199254740991) << std::endl;
std::cout<< (9007199254740992 + 0.0 == 9007199254740992) << std::endl;
std::cout<< (9007199254740993 + 0.0 == 9007199254740993) << std::endl;
输出为
true
true
true
为什么Lua中第三个输出是false
,为什么C++给出的输出都是true
呢?本文结合IEEE-754中关于浮点数的表示机制,分析上述结果出现的原因,同时给出C/C++浮点数进行比较应该注意的事项。
一、IEEE-754浮点数表示机制
1. 表示机制
IEEE-754浮点数中涉及到32, 64, 128位浮点数表示机制,它们的原理类似, n n n位的比特串中第一位是符号位,中间是指数位,后面是小数位,以单精度、双精度,四精度如下表1:
符号位(sign/s) | 指数位(exponent/exp) | 小数位(fraction/frac) | |
---|---|---|---|
Single precision | 31 | 30->23 (8bit) | 22->0 (23bit) |
Double precision | 63 | 62->52 (11bit) | 51->0 (52bit) |
Quadruple precision | 127 | 126->112 (15bit) | 111->0 (112bit) |
下面给出了单精度和双精度浮点数的表示示意图1
浮点数的值由下面的公式1进行计算:
V
=
(
−
1
)
s
×
2
E
×
M
V = (−1)^s × 2^E × M
V=(−1)s×2E×M
- 第一个符号位 s s s为0时,表示正数,为1时,表示负数
- 接下来的 k k k-bit表示指数 E E E, e = e k − 1 . . . e 1 e 0 e=e_k-1...e_1e_0 e=ek−1...e1e0, E E E 由 e x p exp exp( k k k-bit转换为无符号整数)间接表示,但不一定等于 e e e
- 最后的 n n n-bit表示小数 M M M, f = f n − 1 . . . f 1 f 0 f=f_n-1...f_1f_0 f=fn−1...f1f0, M M M 由 f r a c frac frac( n n n-bit转换为小数)间接表示,但不一定等于 f f f
根据 e x p exp exp的编码是否为全0,全1,以及不为全0或全1,浮点数可以分为三类:
- 规格化的浮点数: e x p exp exp的编码不为全0或全1
- 非规格化的浮点数: e x p exp exp的编码为全0
- 特殊值:
e
x
p
exp
exp的编码为全1
- 如果 f r a c frac frac位全为0,表示无穷大( s s s为0为正无穷大, s s s为1为负无穷大)
- 如果 f r a c frac frac位不全为0,表示NaN(Not a Number)
下面以单精度浮点数为例给出了上面三类浮点数的表示如下图2:
对于规格化和非规格化的浮点数,对于公式 V = ( − 1 ) s × 2 E × M V = (−1)^s × 2^E × M V=(−1)s×2E×M,其计算 M M M和 E E E的过程如下表2所示:
b i a s bias bias | E E E | E m i n E_min Emin | E m a x E_max Emax | M M M | |
---|---|---|---|---|---|
规格化浮点数 | 2 k − 1 − 1 2^k-1-1 2k−1−1 | e − b i a s e-bias e−bias | 2 − 2 k − 1 2-2^k-1 2−2k−1 | 2 k − 1 − 1 2^k-1-1 2k−1−1 | 1 + f 1 + f 1+f |
非规格化的浮点数 | 2 k − 1 − 1 2^k-1-1 2k−1−1 | 1 − b i a s 1-bias 1−bias | 2 − 2 k − 1 2-2^k-1 2−2k−1 | 2 − 2 k − 1 2-2^k-1 2−2k−1 | f f f |
2. 优缺点分析
假设8位比特串来表示一个浮点数, k = 4 , n = 3 k=4, n = 3 k=4,n=3, 那么 b i a s = 7 bias = 7 bias=7,我们有下面的表3:
描述 | 位表示 | E E E | M M M | V V V | 十进制值 |
---|---|---|---|---|---|
无穷小 | 1 1111 000 | … | … | … | -inf |
0 | 0 0000 000 | -6 | 0 | 0 | 0.0 |
最小非规格化数 | 0 0000 001 | -6 | 1 8 \\frac18 81 | 1 512 \\frac1512 5121 | 0.001953 |
… | … | … | … | … | … |
最大非规格化数 | 0 0000 111 | -6 | 7 8 \\frac78 87 | 7 512 \\frac7512 5127 | 0.013672 |
最小规格化数 | 0 0001 000 | -6 | 8 8 \\frac88 88 | 8 512 \\frac8512 5128 | 0.015625 |
… | … | … | … | … | … |
最大规格化数 | 0 1110 111 | 7 | 15 8 \\frac158 815 | 1920 8 \\frac19208 81920 | 240 |
无穷大 | 0 1111 000 | … | … | … | inf |
观察上面的表格,可以发现:
- 最大非规格化数和最小规格化数之间是平滑切换的
- 正数和负数是对称的,由符号位决定
- 越靠近0,表示越精确,越远离0,表示越稀疏,越粗略
3. 例子
我们来看整数12345和单精度浮点数12345.0的表示方法:
12345的二进制数0000 0000 0000 0000 0011 0000 0011 1001
对应的浮点数位表示是:
1.100000011100
1
2
∗
2
13
1.1 0000 0011 1001_2 * 2 ^13
1.10000001110012∗213, 那么由
2
k
−
1
−
1
=
2
7
−
1
=
127
2^k-1-1 = 2^7 - 1 = 127
2k−1−1=27−1=127 ,
e
−
127
=
13
e - 127 = 13
e−c++中如何输出保留三位小数的浮点数