数字系统中的浮点表示

Floating point representation in number system

我不知道如何解决这个问题,我知道浮点数的显式、隐式和 IEEE-754 规范化表示,但如何将其分解为小问题。请帮我想象一下。

让我们假设 IEEE-754 单精度浮点数。在这样的浮点数中,你有大约 7 位精度 - 之后你就进入了浮点荒野。

我是什么意思?好吧,假设我有一个数字 = 7654321。我可以将其转换为 32 位浮点值,然后我可以取回那个确切的数字。当数字变得比那个大时,我开始失去精度 - 即数字从浮点数的末尾掉落并丢失。

考虑以下几点:

#include <stdio.h>

int main(int argc, char *argv[])
  {
  float f1 = 7654321, f2 = 987654321;

  printf("f1 = %f   f2 = %f\n", f1, f2);
  }

当我 运行 我得到

f1 = 7654321.000000   f2 = 987654336.000000

希望您看到后说:“说什么?!?!”。 f2 怎么了?

正如我所说,32 位浮点数只有大约 7 位(十进制)精度。如果您尝试将精度超过 7 位的数字放入 32 点浮点变量中,则会失去精度 - 低位数字会丢失。

那么让我们考虑一下您问题中的值:

A =  2.0 * 10^30
B = -2.0 * 10^30
C = 1.0

并且你应该在执行计算时弄清楚你得到什么

X = A + B
X = X + C

Y = A + C
Y = Y + B

好吧,让我们从第一个开始。代入我们得到的值

X = A + B = (2.0 * 10^30) + (-2.0 * 10^30)

幸运的话,X 现在将为零。那么我们有

X = X + C

所以,代入我们得到的值

X = 0.0 + 1.0

所以 X 应该以 1.0 结尾。

好的,这很有趣。下面再看看Y的计算,其实和X的计算是一样的,只是重新排列了一下:

Y = 2.0 * 10^30 + 1.0

这应该给我们结果 2.0 * 10^30。嗯?为什么?!?好吧,2*10^30 超出了浮点数可能的精度(只能保留 7 位精度),因为它代表一个 30 位数字,因此将值 1.0 添加到 2*10^30 不改变它。所以此时Y = 2.0 * 10^30。然后我们将 B = -2.0 * 10^30 添加到它,我们得到 - 是的,零。

所以你最终得到 X = 1.0,Y = 0.0 即使你在头脑中执行这些计算而不考虑计算机中浮点数的精度限制,你也会得到一个值两者均为 1.0.

此处的预期教训是,当您处理浮点值时,运算顺序非常重要,您必须仔细考虑您正在使用的值的大小以计划您的计算,以便你不会以数字糊状结束。

顺便说一句,这里有一个小程序可以实现你的任务:

#include <stdio.h>
#include <math.h>

int main(int argc, char *argv[])
  {
  float A = 2.0 * pow(10, 30), B = -2.0 * pow(10, 30), C = 1.0;
  float X, Y;
  
  X = A + B;
  X = X + C;
  
  Y = A + C;
  Y = Y + B;
  
  printf("X = %f   Y = %f\n", X, Y);
  }

运行 它并打印

  X = 1.000000   Y = 0.000000

Online GDB here