一、计算机存储浮点数的算法

在计算机中,浮点数通常采用IEEE 754标准进行存储,该标准定义了两种主要的浮点数格式:单精度浮点数(32位)和双精度浮点数(64位)。

(一)单精度浮点数

  • 占用32位存储空间。
  • 格式分为三个部分:
    • 符号位(1位):0表示正数,1表示负数。
    • 指数位(8位):用于表示浮点数的指数大小。
    • 尾数位(23位):表示浮点数的小数部分。
      其存储的值计算公式为(−1)sign×1.fraction×2exponent−bias(-1)^{sign}×1.fraction×2^{exponent - bias}(1)sign×1.fraction×2exponentbias(其中signsignsign是符号位,fractionfractionfraction是尾数位表示的小数部分,exponentexponentexponent是指数位的值,对于单精度浮点数,biasbiasbias为127)。

(二)双精度浮点数

  • 占用64位存储空间。
  • 格式同样分为符号位(1位)、指数位(11位)和尾数位(52位)。

二、为什么浮点数不能精确存储

(一)有限的位数

无论是单精度还是双精度浮点数,位数有限。在表示一些无限小数或者非常大/非常小的数时,必然存在精度损失。例如,十进制的0.10.10.1在二进制中是无限循环小数0.00011001100110011……0.00011001100110011……0.00011001100110011……,由于浮点数位数有限,无法精确表示,只能近似存储。

(二)舍入误差

在将十进制数转换为二进制浮点数存储以及进行浮点数运算时,都可能发生舍入误差。例如,0.20.20.20.30.30.3相加,十进制结果为0.50.50.5,但在计算机中,因浮点数精度限制,0.20.20.20.30.30.3不能精确表示,相加结果与0.50.50.5有微小差异。

三、如何判断两个浮点数相等

由于浮点数存在精度问题,不能直接用==判断。通常采用以下方法:

(一)设置误差范围

  1. 定义一个非常小的数作为误差范围,如ϵ=1e−6\epsilon = 1e - 6ϵ=1e6
  2. 判断两个浮点数之差的绝对值是否小于ϵ\epsilonϵ,若是,则认为两浮点数相等。例如:
#include <stdio.h>
#include <math.h>

// 设置误差范围判断两个浮点数是否相等
void compareFloatsWithEpsilon() {
    double epsilon = 1e-6;
    double a = 0.1 + 0.2;
    double b = 0.3;

    if (fabs(a - b) < epsilon) {
        printf("a 和 b 相等\n");
    } else {
        printf("a 和 b 不相等\n");
    }
}

(二)相对误差判断

  1. 计算两个浮点数的相对误差,即两数之差除以其中一个数的绝对值。
  2. 如果相对误差小于给定阈值,则认为两浮点数相等。例如:
// 通过相对误差判断两个浮点数是否相等
void compareFloatsWithRelativeError() {
    double threshold = 1e-6;
    double a = 0.1 + 0.2;
    double b = 0.3;
    double relative_error = fabs(a - b) / (fabs(a) > fabs(b)? fabs(a) : fabs(b));

    if (relative_error < threshold) {
        printf("a 和 b 相等\n");
    } else {
        printf("a 和 b 不相等\n");
    }
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐