3

在此处输入图像描述

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

4

1 回答 1

4

让我们假设 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

在线 GDB 在这里

于 2020-06-23T03:30:27.277 回答