【matlab】数据类型01-数值型变量(整数、浮点数、复数、二进制和十六进制)-二、 浮点数

2.1 双精度和单精度

“浮点”指一组对实数进行编码的数据类型,包括分数和小数。浮点数据类型允许小数点后有不同位数,而定点数据类型在小数点前后则保留特定位数。因此与定点数据类型相比,浮点数据类型可以表示更广范围的数值。

由于计算机在数字表示和存储方面的内存有限,只能表示有限精度的浮点数有限集合。这种有限精度无法精确表示某些数值,因而会限制需要精确值或高精度的浮点计算的准确度。尽管浮点数有其局限性,但其计算速度快且精度和范围足以求解现实世界的很多问题,因此得到广泛使用。

MATLAB® 以双精度或单精度格式表示浮点数。

默认为双精度,但你可以通过一个简单的转换函数将任何数值转换为单精度数值。

(1)创建双精度数据
由于 MATLAB 的默认数值类型是 double 类型,因此可以用简单的赋值语句创建双精度浮点数。

x = 122

可以使用 double 函数将数值数据、字符或字符串以及逻辑数据转换为双精度值。例如,将有符号整数转换为双精度浮点数。

x = int8(120);
y = double(x)

(2)创建单精度数据

使用 single 函数创建单精度数值。

x = single(25.783);

2.2 浮点数的存储

默认情况下,MATLAB 根据 IEEE754 格式构造其 double 和 single 浮点数据类型,并遵循就近舍入,偶数优先舍入模式。

数据以二进制形式存储于计算机。

浮点数 x x x的二进制存储形式如下:
x = − 1 s ⋅ ( 1 + f ) ⋅ 2 e x=-1^s\cdot(1+f)\cdot2^e x=1s(1+f)2e

其中:

  • s 确定符号。
  • f 是满足 0 ≤f< 1 的小数(或尾数)。
  • e 是指数。

sfe 分别由内存中有限数量的位确定,其中 fe 取决于数据类型的精度。

在这里插入图片描述

存储 double 数需要 64 位,如下表所示。

宽度 用法
63 1 存储符号,其中 0 表示正值,1 表示负值,s
6252 11 存储指数,偏移量为 1023 ,e
510 52 存储尾数 ,f

存储 single 数需要 32 位,如下表所示。

宽度 用法
31 1 存储符号,其中 0 表示正值,1 表示负值
3023 8 存储指数,偏移量为 127
220 23 存储尾数

???? 浮点数能表示的最大数量级:

用11个二进制位表示指数,则指数最大值为: 2 11 − 1 = 2047 2^{11}-1=2047 2111=2047
偏移量是1023,则最大指数为:2047 - 1023 = 1024,对应的数量级就是 2 1024 2^{1024} 21024 1 0 308 10^{308} 10308,负数则是 1 0 − 308 10^{-308} 10308

????浮点数能保存的十进制的最多有效位数:

以双精度为例:52位(二进制)表示尾数,一个2进制能表示的十进制数的位数是 l o g 10 2 log_{10}2 log102:。二进制形式存储尾数时候,最高位默认位1,53个二进制位能表示的十进制数的位数是:
53 ∗ l o g 10 2 ≈ 15.96 53*log_{10}2 \approx15.96 53log10215.96

所以double类型存储数据的有效位数是15到16位(如果是一个整数则是最大为2^53,即flinrmax)。

同理single最多可以精确存储6到7位有效数字。

超过有效位数的时候,超过的部分就可能丢失精度。

在这里插入图片描述

即,double使用64个二进制位存储十进制数,这64个二进制位只有52个二进制位来存储尾数,对应十进制的15到16位有效数字

???? 浮点数的大小比较问题:

主要是小数部分,小数转为二进制有时候是无限循环的,但是一个double最多使用52位来存储小数部分对应的二进制,有限的二进制位就不能精确表示这个小数,只是无限精确。即使精确到99.99999999999%也不是等于。

比如 0.1+0.2 和 0.3 是不相等的。因为0.1和0.2对应的52位(尾数)二进制相加后和0.3的二进制不同:

在这里插入图片描述

转换 0.1 为二进制

  1. 0.1 * 2 = 0.2 → 整数部分是 0,记录下来,剩余部分是 0.2。
  2. 0.2 * 2 = 0.4 → 整数部分是 0,记录下来,剩余部分是 0.4。
  3. 0.4 * 2 = 0.8 → 整数部分是 0,记录下来,剩余部分是 0.8。
  4. 0.8 * 2 = 1.6 → 整数部分是 1,记录下来,剩余部分是 0.6。
  5. 0.6 * 2 = 1.2 → 整数部分是 1,记录下来,剩余部分是 0.2。
  6. 0.2 * 2 = 0.4 → 整数部分是 0,记录下来,剩余部分是 0.4。

可以看到,0.1 的小数部分开始循环重复(0.1 = 0.00011001100110011...),这是一个无限循环的二进制小数。

浮点数运算后,可以使用如下方式比较2个运算结果:

x+y-0.3<eps

eps表示浮点相对精度,即2个距离最近的(双精度)浮点数之间的距离。d = eps("single")则为2个距离最近的single之间的距离。

>> eps

ans =

   2.2204e-16

2.3 浮点数的最值

double_max = realmax('double')
double_min = realmin('double')

single_max = realmax('single')
single_min = realmin('single')

在这里插入图片描述

double_max = 1.7977e+308表示 1.797 ∗ 1 0 308 1.797*10^{308} 1.79710308。这个数是极大的,是太阳质量的数量级的10多倍。

超过这个范围的数记为Inf,-Inf

2.4 浮点数的“四舍五入”

❄️ (1)直接使用int8等转换函数转换为整数类型,规则是,小数部分四舍五入;

❄️ (2)round函数:支持多种转换方案

  • a. 小数部分四舍五入,结果为double类型:round(x)

  • b. 四舍五入到 N 位数(N可用为正负、零,从小数点向两边数起):Y = round(X,N)

  • c. 指定四舍五入类型:Y = round(X,N,type)
    type的取值有"decimals" (默认) | "significant",前者指定保留的小数位数,等同于:Y = round(X,N)
    若使用第二个参数,四舍五入到具有 N 个有效位数的最近数值:

num = 1234.456
num_round_2 = round(num,2,'significant')
num_round_3 = round(num,3,'significant')

输出分别是12001230

  • d.指定处理方向,结值处理方向,指定为以下值之一:
Y = round(___,TieBreaker=direction)

“fromzero” - 将结值朝偏离零的方向舍入到模更大的最接近的整数。

“tozero” - 将结值朝零方向舍入到模更小的最接近的整数。

“even” - 将结值舍入到最接近的偶数。

“odd” - 将结值舍入到最接近的奇数。

“plusinf” - 将结值朝正无穷大方向舍入到更大的最接近的整数。

“minusinf” - 将结值朝负无穷大方向舍入到更小的最接近的整数。

例:

num = 1.5
num_round_1 = round(num,'TieBreaker','fromzero') % 输出是2
num_round_2 = round(num,'TieBreaker','tozero')   % 输出是1

上面2个参数主要是针对小数等于0.5的情况。而,num = 1.2,结果均为1,num=1.7,结果均为2。

推荐使用round进行正常四舍五入,带方向的可以使用下列函数:

❄️ (3)floor(X)函数:将 X 的每个元素四舍五入到小于或等于该元素的最接近整数。
❄️ (4)ceil(X)函数:将 X 的每个元素四舍五入到大于或等于该元素的最接近整数。
❄️ (5)fix(X) 函数:将 X 的每个元素朝零方向四舍五入为最近的整数。此操作实际上是通过删除 X 中每个数的小数部分,将它们截断为整数:

在这里插入图片描述

2.5 浮点数的算术运算

就几条规则:

  1. double类型可用和任意类型进行运算。常见:single、double、char、logic、任意int类型
    • 和single运算的结果是single;
    • 和整数运算结果为对应的整数类型,且结果受到对应整数类型的最值限制;
    • 其它结果都为double类型。
  2. single类型只能和以下类型运算:single、double、char、logic(即不能和整数运算)。结果都为single

2.6 意外:舍入误差、抵消、淹没和中间转换

之前已经说过了,浮点数可能需要无限个二进制位来精确存储,但这不现实,实际上只能用64位来存储一个浮点数,所以会导致一些不准确或者意料之外的结果。

意外的结果并非 MATLAB 中的 Bug,任何使用浮点数的软件都会出现这种情况。如果需要数值的精确有理表示形式,请考虑使用 Symbolic Math Toolbox™

(1)舍入误差:

浮点数的有限精度表示可能导致舍入误差。例如 π \pi π

>> sin(pi)

ans =

   1.2246e-16

当对浮点数执行许多运算时,误差会不断累积和复合,舍入误差最为显著。最佳做法是尽可能减少运算次数。

(2)抵消:根据 eps 的测量,从数量级大致相同的一个数中减去另一个数时,可能发生抵消。

(3)淹没:对数量级相差特别大的浮点数执行运算时,可能发生淹没。

(3)中间转换:使用不同数据类型执行算术时,中间计算和转换可能会产生意外的结果。

在这里插入图片描述

上一篇:在openi平台 基于华为*深度计算平台 openmind 动手实践


下一篇:std::sort的底层原理(混合排序算法)